unity 热力图学习

1.单纯使用CPU进行初步的思路学习

思路:使用rawimage充当热力图,rawimage位置定死,在rawimage对应的三维地面上创建两个transform,分别对应左下角与右上角,将需要进行热力图显示的设备框在这个范围内。然后,在代码中使用rawimage本身的宽高和三维对应点的x z 差值,计算出设备在rawimage上的对应点。将设备温度转换为对应颜色,将颜色赋值给前面算出来的像素点。

代码:

复制代码
using SpringGUI;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TestHeatMap : MonoBehaviour
{
    public RawImage heatmap;

    public List<GameObject> equipment;

    public Transform statPos, endPos;

    private float rawimageWidth, rawimageHeight;

    private float realWidth, realHeight;

    public Color maxColor = Color.red;

    public Color minColor = Color.blue;

    public float maxValue = 60;

    public float minValue = 10;

    /// <summary>
    /// 颜色衰减范围
    /// </summary>
    public float radius = 10;

    public enum FalloffType
    {
        Linear,
        Quadratic,
        Gaussian
    }

    public FalloffType falloffType = FalloffType.Linear;

    private Texture2D tex;

    private Color[,] colorBuffer;

    private void Start()
    {
        rawimageWidth = heatmap.rectTransform.rect.width;

        rawimageHeight = heatmap.rectTransform.rect.height;

        realWidth = endPos.position.x - statPos.position.x;

        realHeight = endPos.position.z - statPos.position.z;

        tex = new Texture2D((int)rawimageWidth, (int)rawimageHeight);

        colorBuffer = new Color[(int)rawimageWidth, (int)rawimageHeight];

        Color[] pixels = new Color[(int)rawimageWidth * (int)rawimageHeight];

        for (int i = 0; i < rawimageWidth; i++)
        {
            for (int j = 0; j < rawimageHeight; j++)
            {
                colorBuffer[i, j] = Color.clear;
            }
        }

        // 2. 放置"热点" (只标记中心点,不画圆)
        List<Vector3> points = new List<Vector3>(); // 存储 (x, y, intensity)

        for (int i = 0; i < equipment.Count; i++)
        {
            Vector3 pos = equipment[i].transform.position;

            int x = (int)((pos.x - statPos.position.x) / realWidth * rawimageWidth);

            int y = (int)((pos.z - statPos.position.z) / realHeight * rawimageHeight);

            float intensity = float.Parse(equipment[i].name) / maxValue; // 归一化强度

            points.Add(new Vector3(x, y, intensity));
        }

        // 3. 卷积核(定义热量如何扩散)
        int blurRadius = 30; // 扩散范围(调大这个值!)
        float sigma = 15f;   // 扩散平滑度

        // 4. 遍历画布,计算每个像素受所有热点的影响
        for (int y = 0; y < rawimageHeight; y++)
        {
            for (int x = 0; x < rawimageWidth; x++)
            {
                float totalHeat = 0;
                foreach (var p in points)
                {
                    float dist = Vector2.Distance(new Vector2(x, y), new Vector2(p.x, p.y));
                    // 高斯权重
                    float weight = Mathf.Exp(-(dist * dist) / (2 * sigma * sigma));
                    totalHeat += p.z * weight;
                }
                // 根据总热量映射颜色
                pixels[y * (int)rawimageWidth + x] = Color.Lerp(minColor, maxColor, totalHeat);
            }
        }

        tex.SetPixels(pixels);
        tex.Apply();
        heatmap.texture = tex;
    }

    /// <summary>
    /// 绘制圆形衰减
    /// </summary>
    /// <param name="centerx"></param>
    /// <param name="centery"></param>
    /// <param name="baseColor"></param>
    void DrawCicularGradient(int centerx, int centery, Color baseColor)
    {
        int radiusInt = Mathf.CeilToInt(radius);

        for (int x = centerx - radiusInt; x <= centerx + radiusInt; x++)
        {
            for (int y = centery - radiusInt; y <= centery + radiusInt; y++)
            {
                if (x >= 0 && x < rawimageWidth && y >= 0 && y < rawimageHeight)
                {
                    float distance = Mathf.Sqrt(Mathf.Pow(x - centerx, 2) + Mathf.Pow(y - centery, 2));

                    if (distance <= radius)
                    {
                        float falloff = CalculateFalloff(distance);

                        Color pixelColor = baseColor * falloff;

                        colorBuffer[x, y] += pixelColor;

                        //限制颜色不超过1
                        colorBuffer[x, y].r = Mathf.Clamp01(colorBuffer[x, y].r);
                        colorBuffer[x, y].g = Mathf.Clamp01(colorBuffer[x, y].g);
                        colorBuffer[x, y].b = Mathf.Clamp01(colorBuffer[x, y].b);
                        colorBuffer[x, y].a = Mathf.Clamp01(colorBuffer[x, y].a);
                    }
                }
            }
        }
    }

    void ApplyColorBufferToTexture()
    {
        for (int x = 0; x < rawimageWidth; x++)
        {
            for (int y = 0; y < rawimageHeight; y++)
            {
                tex.SetPixel(x, y, colorBuffer[x, y]);
            }
        }

        tex.Apply();
    }

    /// <summary>
    /// 计算衰减因子
    /// </summary>
    float CalculateFalloff(float normalizedDistance)
    {
        switch (falloffType)
        {
            case FalloffType.Linear:
                return 1 - normalizedDistance;
            case FalloffType.Quadratic:
                return 1 - normalizedDistance * normalizedDistance;
            case FalloffType.Gaussian:
                // 高斯衰减:e^(-距离² × 5)
                return Mathf.Exp(-normalizedDistance * normalizedDistance * 5);
            default:
                return 1f - normalizedDistance;
        }
    }
}

代码运行效果:

相关推荐
2501_9318197037 分钟前
方言标注标准化模板迭代优化诉求 泸州话标注公司学习信实翻译模板迭代方法论
学习
tju新生代魔迷1 小时前
Python学习日记5
学习
小唔w2 小时前
武汉外籍人员子女学校择校观察:枫叶教育信息整理
学习
for_ever_love__2 小时前
python基础语法学习: 装饰器
python·学习·装饰器·装饰器模式
狂云歌2 小时前
AI学习之function calling&mcp
人工智能·学习·ai·ai编程
FAREWELL000752 小时前
学习笔记-热更新导航
笔记·学习
wuhuhuan2 小时前
【JMeter 学习打卡 Day 7】从会用到会用对,完成一次完整压测
学习·jmeter
tju新生代魔迷2 小时前
Python学习日记2
python·学习
mlidongfeng2 小时前
[AI][昇腾950]TA 学习
数据库·学习
ヾChen3 小时前
ESP32 OTA 踩坑实录
stm32·单片机·嵌入式硬件·物联网·学习