首先是热力图信息类:

using System;
using UnityEngine;

[Serializable]
public class HeatMapInfo
{
	public Rect rect = Rect.zero;
	public float pixelDensity = 1;
	public float valBase = 0;
	public float valRange = 1;
	public PercentColor[] ribbon;//色带
	public Color colorMulti = Color.white;
	public float influence = 100;//点影响范围
	public PosVal[] posVals;
}

[Serializable]
public class PercentColor
{
	public float percent = 0;
	public Color color = Color.clear;
	public PercentColor(float percent, Color color)
	{
		this.percent = percent;
		this.color = color;
	}
}

[Serializable]
public class PosVal
{
	public Vector3 pos;
	public float val;
	public PosVal(Vector3 pos, float val)
	{
		this.pos = pos;
		this.val = val;
	}
}

然后是热力图的实现代码:

using UnityEngine;
using UnityEngine.Rendering.Universal;

public class HeatMap : MonoBehaviour
{
	static public HeatMap instance;

	void Awake()
	{
		instance = this;
	}

	[SerializeField]
	DecalProjector decalProjector;

	void Start()
	{
		SceneLoader.instance.AddActBeforeActiveNewScene(CancelHeatMap);
	}

	HeatMapInfo info;
	public void SetHeatMap(HeatMapInfo info)
	{
		this.info = info;
		if (this.info == null) return;
		//
		decalProjector.gameObject.SetActive(true);
		decalProjector.pivot = new Vector3(this.info.rect.x + this.info.rect.width * 0.5f, this.info.rect.y + this.info.rect.height * 0.5f, 0);
		decalProjector.size = new Vector3(this.info.rect.width, this.info.rect.height, 2000);
		Texture2D tex2D = GetHeatMap(this.info);
		decalProjector.material.SetTexture("_MainTex", tex2D);
		decalProjector.material.SetColor("_Color", this.info.colorMulti);
	}

	public void CancelHeatMap()
	{
		info = null;
		decalProjector.gameObject.SetActive(false);
	}

	public void UpdateHeadMap(PosVal[] posVals)
	{
		if (info == null) return;

		info.posVals = posVals;
		Texture2D tex2D = GetHeatMap(this.info);
		decalProjector.material.SetTexture("_MainTex", tex2D);
	}

	public Texture2D GetHeatMap(HeatMapInfo info)
	{
		float pixelDensity = info.pixelDensity * 0.05f;
		int texW = (int)(info.rect.width * pixelDensity);
		int texH = (int)(info.rect.height * pixelDensity);
		Texture2D texHeatMap = new Texture2D(texW, texH);
		//
		float unitU = 1.0f / texW;
		float unitV = 1.0f / texH;
		Vector2 pos = new Vector2();
		float influence = info.influence;
		PercentColor[] ribbon = info.ribbon;
		Color colorOutHot = ribbon[ribbon.Length - 1].color;
		float sqrtInfluence = influence * influence;
		for (int i = 0; i < texW; i++)
		{
			pos.x = unitU * i * info.rect.width + info.rect.x;
			for (int j = 0; j < texH; j++)
			{
				Color color = colorOutHot;
				pos.y = unitV * j * info.rect.height + info.rect.y;
				foreach (PosVal pv in info.posVals)
				{
					float sqrtDist = (pos - new Vector2(pv.pos.x, pv.pos.z)).sqrMagnitude;
					if (sqrtDist > sqrtInfluence) continue;
					//
					float pointDensity = (pv.val - info.valBase) / (info.valRange);
					pointDensity = Mathf.Clamp01(pointDensity);

					float dist = Mathf.Sqrt(sqrtDist);
					float pe = dist / influence;
					float percent = pe + (1 - pe) * (1 - pointDensity);
					Color ribbonColor = Color.black;
					if (Mathf.Approximately(percent, 0))
					{
						ribbonColor = ribbon[0].color;
					}
					else if (Mathf.Approximately(percent, 1))
					{
						ribbonColor = ribbon[ribbon.Length - 1].color;
					}
					else
					{
						for (int k = 1; k < ribbon.Length; k++)
						{
							if (percent < ribbon[k].percent)
							{
								float p = (percent - ribbon[k - 1].percent) / (ribbon[k].percent - ribbon[k - 1].percent);
								ribbonColor = Color.Lerp(ribbon[k - 1].color, ribbon[k].color, p);
								break;
							}
						}
					}
					color += ribbonColor * (1 - pe);
				}
				texHeatMap.SetPixel(i, j, color);
			}
		}

		texHeatMap.Apply();
		return texHeatMap;
	}
}

最后是贴花Shader

基于贴花的热力图呈现方法参考-LMLPHP

 

 

07-27 21:26