Unity 3D 热力图(一)

                                                效果图

一、动态创建mesh

首先需要创建一个Mesh,当然这不是必须的,可以使用plane,自己创建主要方便控制精度。修改顶点高度,如果顶点不够可能不够平滑,太多又浪费资源。因此最好根据实际需求大小生成。

 private void CreateMesh()
    {
        float perxlength = mapSize.x /(meshSize.x - 1);
        float perzlength = mapSize.y / (meshSize.y - 1);


        int totalcount = (int)meshSize.x * (int)meshSize.y;
        Vector3[] vertexs = new Vector3[totalcount];
        Vector3[] normals = new Vector3[totalcount];

        int[] triangles = new int[((int)meshSize.x - 1) * ((int)meshSize.y - 1) * 2 * 3];

        int trianglesindex = 0;
        for (int i = 0; i < meshSize.y; i++)
        {

            for (int j = 0; j < meshSize.x; j++)
            {
                float x = perxlength * j;
                float z = perzlength * i;

                int index = i * (int)meshSize.x + j;

                vertexs[index] = new Vector3(x, 0, z);
                normals[index] = transform.up;

                if(j != meshSize.x - 1&& i != meshSize.y - 1)
                {
                    triangles[trianglesindex] = j + i * (int)meshSize.x;
                    trianglesindex++;
                    triangles[trianglesindex] = j + 1 + (int)meshSize.x + i * (int)meshSize.x;
                    trianglesindex++;
                    triangles[trianglesindex] = j + 1 + i * (int)meshSize.x;
                    trianglesindex++;
                    triangles[trianglesindex] = j + i * (int)meshSize.x;
                    trianglesindex++;
                    triangles[trianglesindex] = j + (int)meshSize.x + i * (int)meshSize.x;
                    trianglesindex++;
                    triangles[trianglesindex] = j + 1 + (int)meshSize.x + i * (int)meshSize.x;
                    trianglesindex++;
                }
            }
        }

        Mesh mesh = new Mesh();
        mesh.vertices = vertexs;
        mesh.normals = normals;
        mesh.triangles = triangles;

        GetComponent<MeshFilter>().mesh = mesh;
    }

二、Shader修改顶点高度

mesh是一个平面,顶点高度的修改在Shader中完成。具体高度根据热力数据计算,因为热力数据是某一个点的数据,所以需要计算扩散的热力值。

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

Shader "Effect/thermograph3d"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}

        _Color1("_Color1" , Color) =(1,1,1,1)
        _Color2("_Color2" , Color) =(1,1,1,1)
        _Color3("_Color3" , Color) =(1,1,1,1)
        _Color4("_Color4" , Color) =(1,1,1,1)

        _Alpha("Alpha" , Range(0,1)) = 0.5
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" "Queue" ="Transparent"}

        Blend SrcAlpha OneMinusSrcAlpha

        Pass
        {
            ZWrite On
            ColorMask 0
        }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "thermpgraph.hlsl"


            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                float temp : TEXCOORD1;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            float _Alpha ;

            vector tempData[500];

            float tempcount;

            float perTempHeight;

            float maxRefrence;


            float GetHeight(float2 vertex)
            {
                float height = 0;
                for(int i = 0;i<tempcount;i++)
                {
                     float deltax = vertex.x  - tempData[i].x;
                     float deltay = vertex.y  - tempData[i].y;

                     float distance = sqrt(deltax * deltax + deltay * deltay);
                     if(distance > maxRefrence)
                           continue;
                     float centerheight = perTempHeight * tempData[i].z;
                     float releaseDis = 1- (cos(radians(180*(maxRefrence - distance) / maxRefrence)) + 1) / 2;
                     float nowHeight = centerheight *  releaseDis ;

                     if(nowHeight != 0)  
                     height = nowHeight / (nowHeight + height) * nowHeight + height;
                }

                return  height;
            }

            v2f vert (appdata v)
            {
                v2f o;

                float3 worldpos = mul(unity_ObjectToWorld , v.vertex);
                v.vertex.y = GetHeight(worldpos.xz);
                o.temp = v.vertex.y / perTempHeight;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                              
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                fixed4 color = Temp2Color(i.temp , col ,_Alpha);

                clip (color.a - 0.01); 
                return color;
            }
            ENDCG
        }
    }
}

            float colorLine[30];

            fixed4 _Colors[30];

            float colorcount;
          
            fixed4 Temp2Color(float temp , fixed4 color , float _Alpha )
            {
                float lerpnum = 10;
                color.a = 0;
                for(int i = 0 ; i < colorcount ; i++)
                {
                    if(temp > colorLine[i])
                    {
                        if(i == 0)
                           return fixed4(_Colors[i].rgb , _Colors[i].a * _Alpha);
                        else
                        {
                            fixed4 tempcolor = lerp(_Colors[i] ,_Colors[i - 1] , (temp - colorLine[i]) / (colorLine[i - 1] - colorLine[i]));
                            tempcolor.a = _Alpha * tempcolor.a;
                            return tempcolor;
                        }
                    }
                }
                return color;
            }

这是shader的完整代码,高度计算部分可以自己根据算法修改,这个算法没有根据,只是满足变化曲线的随便一个计算方式。第二部分是thermpgraph.hlsl代码,主要是融合颜色,让颜色可以很平稳的过渡。

融合部分也是没有根据的算法,不能用到检测环境中,具体算法也需要按照温度变化算法计算的。

三、思路

在做温度图的时候,首先保证可以创建虚拟数据,所以做了一个Editor工具,可以通过点击,然后添加点击点为温度点。

保存温度坐标点的时候,最好用全局坐标,不要用相对Mesh的坐标。用全局坐标,可以很好接入经纬度数据,只要将温度经纬度转换为全局坐标,然后赋值到温度图上就行。

因为是在一个等密度的平面上生成的温度图,所以在精度要求高,而且面积特别大的场景中,可能会形成几百万的三角。这可能会造成性能问题,所以最好可以根据经纬度坐标点的位置动态生成密度不均匀的平面,但是生成的时候可能会有一丝卡顿。因为这种大场景很少见,我就遇到的一次,然后通过多个温度图分布在目标点集中位置解决了。所以没有优化这部分。

  • 16
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 21
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值