[zhang273162308] Unity&Shader案例篇—地图上热图分布

一、介绍

        在2维平面地图上随机或者指定位置生成一系列的热量、能源或者其他需要表示的信息的分布图。可以通过切换不同的贴图表示不同的信息,如图所示表示的是该地区的降水量的变化


如图所示为表示该地区的温度变化分布图


二、实现

       在贴图的的某个位置处绘制指定半径的圆圈,然后调整圆圈的强度也即透明度。因此Shader部分会定义这两类变量,因为Shader里面不能定义没有长度的数组,只能一开始给个固定比较大的100作为初始长度,在代码里传这个数组变量的时候只要不超过这个数组的长度的参数都是可以的。当然你穿了101个数组的参数也不会报错,但是超出100的肯定也不会被shader代码使用到。代码

[mw_shl_code=csharp,true]                        //自定义变量
                        uniform int _Points_Length = 0;
                        uniform float3 _Points[100];                // (x, y, z) = 位置
                        uniform float2 _Properties[100];        // x = 半径, y = 透明度
                        sampler2D _HeatTex;[/mw_shl_code]

然后,计算每个分布点位置相对世界坐标原地的距离,再结合强度就可以都到一个输出的透明度值。片段着色器代码为:

[mw_shl_code=csharp,true]
                        half4 frag(vertOutput output) : COLOR
                        {
                                half h = 0;
                                for (int i = 0; i < _Points_Length; i++)
                                {
                                        // 计算每一个分布点位置的距离
                                        half di = distance(output.worldPos, _Points.xyz);

                                        half ri = _Properties.x;
                                        half hi = 1 - saturate(di / ri);

                                        h += hi * _Properties.y;
                                }

                               
                                h = saturate(h);
                                half4 col = tex2D(_HeatTex, fixed2(h, 0.5));
                                return col;
                        }[/mw_shl_code]

接下来编写控制脚本,这里写了一个随机的位置、半径和强度。

最后要得到如上图所示的闪烁的热图效果,就是在已有的点位置上加一个噪声处理,如:

[mw_shl_code=csharp,true]using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class HeatMap : MonoBehaviour {

    [SerializeField] private int countPoint;
   [SerializeField] private Material heatMat;

    [SerializeField]
    private Vector4[] pointPoses;
    [SerializeField]
    private Vector4[] pointProper;

   
    private void Awake()
    {
        heatMat.SetFloatArray("_Points", new float[countPoint]);
    }
    // Use this for initialization
    void Start () {

        pointPoses = new Vector4[countPoint];
        pointProper = new Vector4[countPoint];

        for (int i = 0; i < pointPoses.Length; i++)
        {
            pointPoses = new Vector2(Random.Range(-0.9f, 0.9f), Random.Range(-0.5f, 0.5f));
            pointProper = new Vector2(Random.Range(0f, 0.25f), Random.Range(-0.25f, 1f)); // (Radius, Intensities)
        }

        heatMat.SetVectorArray("_Properties", pointProper);
        heatMat.SetInt("_Points_Length", countPoint);
        }
       
        // Update is called once per frame
        void Update () {
        for (int i = 0; i < countPoint; i++)
        {
            pointPoses += new Vector4(Random.Range(-0.1f, +0.1f), Random.Range(-0.1f, +0.1f), 0f, 0f) * Time.deltaTime;
        }
        heatMat.SetVectorArray("_Points", pointPoses);
       // heatMat.SetVectorArray("_Properties", pointProper);
    }
}
[/mw_shl_code]

三、总结

完整的工程文件下载地址为

游客,如果您要查看本帖隐藏内容请回复



感谢分享  感谢分享
u9ipoiuouiouioiuoiu
  • 地板 3084
  • 2018-7-9 19:30:27
感谢分享
6666  最近也想搞 一堆这个东西
666666
666666666666666666
  • 8# hzwlm
  • 2018-7-9 22:54:51
这么好的东西。
  • 9# zisen
  • 2018-7-9 23:07:42
感谢分享
  • 10# vtbox
  • 2018-7-9 23:46:10
谢谢~~~~~~~~~~~~
謝謝分享,研究一下。
感谢分享  感谢分享
实验了一下UP的工程,热点的生成似乎不能动态变化,增加在工程运行的时候改变countPoint就会报错
  • 14# 橙瘾
  • 2018-7-10 08:19:19
谢谢分享
钱钱钱钱钱钱钱钱钱钱钱钱钱钱钱