Unity云图渲染效果

需求

根据有限元分析后处理结果(应力等),将云图效果在Unity中复现同样的效果

需要准备的数据

从有限元分析软件(Abaqus、Ansys等)将模型结点数据进行导出

实现原理

Step1 通过C#根据结点(相当于模型顶点)数据大小将数据转化由红到蓝颜色区间的颜色(采用HSV色彩模型以便于获取纯色彩),获得一个模型顶点的Color数组;
Step2 将颜色传入着色器进行处理(AppToVert、VertToFrag),并通过纹理映射的方式从纹理贴图中获取相应的颜色值。

代码展示

1、C#代码。

public class CloudMapRendering
{
    public static Color[] CalculateModelVerticeColors(float[] physicsDatas)
    {
        colorDatas = new Color[physicsDatas.Length];
        float[] hueColorH = new float[physicsDatas.Length];
        float max = physicsDatas.GetMax();
        //当有限元网格结点值全为0时,颜色全为蓝
        if (max == 0)
        {
            for (int i = 0; i < physicsDatas.Length; i++)
            {
                colorDatas[i] = Color.blue;
            }
            return;
        }
        float min = physicsDatas.GetMin();
        float range = max - min;
        for (int i = 0; i < physicsDatas.Length; i++)
        {
            hueColorH[i] = 2.0f / 3 * (max - physicsDatas[i]) / range;
            colorDatas[i] = Color.HSVToRGB(hueColorH[i], 1, 1);
        }
        return colorDatas;
    }
}
public static class ArrayExtension
{
    public static float GetMax(this float[] vs)
    {
        float max = 0;
        for (int i = 0; i < vs.Length; i++)
        {
            if (vs[i] > max)
            {
                max = vs[i];
            }
        }
        return max;
    }
    public static float GetMin(this float[] vs)
    {
        float min = 0;
        for (int i = 0; i < vs.Length; i++)
        {
            if (vs[i] < min)
            {
                min = vs[i];
            }
        }
        return min;
    }
}

新建一个C#脚本挂在渲染模型上,调用上面的CalculateModelVerticeColors方法,并通过MeshFilter中的colors属性将计算值赋给colors属性。

2、着色器部分。

Shader "Custom/testCloudMapWireframeShader"
{
    Properties
    {
		_Texture("Main Tex",2D) = ""{}
	}
    SubShader
    {
		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			struct a2v {
				float4 vertex:POSITION;
				fixed4 color : COLOR;
				float4 texcoord:TEXCOORD0;
			};

			struct v2f {
				float4 position:SV_POSITION;
				float3 color:COLOR0;
				float4 uv:TEXCOORD1;
			};

			sampler2D _Texture;
			float4 _UVposition;
			//由于着色器用RGB进行计算,因此先转换为HSV
			float3 RGB2HSV(float3 c)
			{
				float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
				float4 p = lerp(float4(c.bg, K.wz), float4(c.gb, K.xy), step(c.b, c.g));
				float4 q = lerp(float4(p.xyw, c.r), float4(c.r, p.yzx), step(p.x, c.r));

				float d = q.x - min(q.w, q.y);
				float e = 1.0e-10;
				return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
			}
			//根据HSV颜色值映射到对应的纹理坐标进行纹理采样
			float3 ColorConvert(float3 originalHSVc)
			{
				return tex2D(_Texture, (1,(1 - originalHSVc.x) * 3) * step(2.0 / 3.0, originalHSVc.x) + (1,originalHSVc.x * 3 / 2) * step(originalHSVc.x, 2.0 / 3.0));
			}
			v2f vert(a2v v)
			{
				v2f f;
				f.position = UnityObjectToClipPos(v.vertex);
				f.color = v.color;
				f.uv = v.texcoord;
				return f;
			}

			fixed4 frag(v2f f) :SV_Target
			{
				float3 convertedColor = RGB2HSV(f.color);
				f.color = ColorConvert(convertedColor);
				return fixed4(f.color,1);
			}
			ENDCG
		}
		}
    FallBack "Diffuse"
}

纹理贴图

一张常见的颜色梯度图(左红右蓝)
在这里插入图片描述

后记

笔者第一次写文章,有很多地方都没有表述清楚,大家有问题或者意见也欢迎评论。