前言
在工业可视化的项目中,我们还会经常遇到一个需求,就是显示某个设备的温度信息,或者是显示一间房间的温度信息,这里我们就需要用到一个组件叫温度/热力图。需要实现一个温度图又一次需要用到我们的网格和shader,下面我们来讲解一下实现的原理和最终的效果。
实现效果
以前大概区分我三个版本,版本之前没有本质区别,只是更改Shader已达到不同的使用场景和最佳的运行效果。
- 不支持透明的单面可见版
不支持透明的双面可见版
支持透明且双面可见版
主要内容
- 绘制网格
- 编写Shader
- 赋颜色值
详细设计
绘制网格
网格的绘制详细教程参见我的另一篇文章,这里不再详细讲解。
如果你不明白如何利用代码来绘制网格,参见我的另一篇博文,非常详细的讲解了网格绘制中的主要内容点。
Unity Shader(一) Lowpoly动态低多边形 (QQ登录界面低边动画)
编写Shader
- 基础版
Shader "HeatMap/HeatMap Easy"
{
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct a2v
{
float4 pos : POSITION;
fixed4 color : COLOR;
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
};
v2f vert( a2v i )
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP,i.pos);
o.color = i.color;
return o;
}
fixed4 frag( v2f i ) : COLOR
{
return i.color;
}
ENDCG
}
}
}
- 双面不透明版
将基础版的改为双面不透明,只需要将渲染通道中Shader默认的剔除属性更改为关闭剔除即可Cull OFF
Pass
{
Cull OFF
CGPROGRAM
//和基础版相同
ENDCG
}
- 双面透明版
再讲双面不透明版更改为支持透明版本,只需要将渲染类型设置为Transparent和渲染队列设置为Transparent,在渲染通道中开启透明混合属性即可Blend SrcAlpha OneMinusSrcAlpha。
Properties
{
_Alpha("Alpha",Range(0,1)) = 0.8
}
SubShader
{
Tags { "RenderType"="Transparent" "Opaque"="Transparent" }
Pass
{
Cull OFF
Blend SrcAlpha OneMinusSrcAlpha
//和基础版相同
CGPROGRAM
}
}
赋颜色值
本组件预留的接口是导入一个二维的温度数组,所以如果你有真实的温度数据,你可以使用我提供的二维数组的接口,也可以自己再添加一个新的接口,在接口中将数据赋值到对应的顶点的color属性即可。
由于没有真实的温度数据,我们利用算法模拟一些数据导入,以下是模拟的算法。
- 赋值颜色大致步骤:
- 初始化二维数组
- 抽取随机点,产生高温值,并产生递减趋势,并生成的温度值覆盖二维数组
- 给顶点的color属性赋值
- 生成网格,添加使用以上编写shader的材质球
初始化二维数组
根据我们录入的数据精度,产生二维数组,我们假定生成一个长宽唯独均为100的二维数组
// 初始化算法
private float[,] InitTemperatures()
{
// vertical 和 horizontal 均为100
float[,] temperature = new float[vertical , horizontal];
for (int i = 0; i < vertical ; i++)
for ( int j = 0 ; j < horizontal ; j++ )
// 假定正常温度为50度低于50度均为正常温度
temperature[i , j] = 50;
return temperature;
}
产生随机高温点
将外界产生的初始化温度通过接口Inject方法传入我们的组件HeatMap中。因为没有真实的温度数据,所以我们需要调用HeatMap中的随机高温点方法来产生一些温度数据。如下:
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class HeatMap : MonoBehaviour
{
public void Inject( float[,] temperature )
{
this.temperature = temperature;
this.horizontal = temperature.GetLength(1);
this.vertical = temperature.GetLength(0);
// 利用随机产生高温点的算法添加6个高温点
RandomTeamperature(99 , 50 , 0 , 45 , ref this.temperature);
RandomTeamperature(89 , 50 , 0 , 25 , ref this.temperature);
RandomTeamperature(79 , 50 , 0 , 30 , ref this.temperature);
RandomTeamperature(69 , 50 , 0 , 33 , ref this.temperature);
RandomTeamperature(89 , 50 , 0 , 50 , ref this.temperature);
RandomTeamperature(79 , 50 , 0 , 22 , ref this.temperature);
meshFilter.mesh = DrawHeatMap();
// 赋值颜色
AddVertexColor();
}
// 随机在某个点产生高温数据,并按minD和maxD温度范围来生成模拟数据
// minD和maxD为以当前高温点为中心的生效范围
// from为最高温度,to为最低温度
private void RandomTeamperature( float from , float to, int minD , int maxD , ref float[,] temperatures )
{
// 产生随机点
int randomX = Random.Range(3 , horizontal);
int randomY = Random.Range(3 , vertical);
float maxTweenDis = maxD - minD;
float offset = to - from;
for ( int i = randomX - maxD ; i < randomX + maxD ; i++ )
{
for ( int j = randomY + maxD ; j > randomY - maxD ; j-- )
{
if ( i < 0 || i >= horizontal )
continue;
if ( j < 0 || j >= vertical )
continue;
float distance = Mathf.Sqrt(Mathf.Pow(randomX - i , 2) + Mathf.Pow(randomY - j , 2));
if ( distance <= maxD && distance >= minD )
{
float offsetDis = distance - minD;
float ratio = offsetDis / maxTweenDis;
float temp = from + ratio * offset;
// 只有比当前点温度高才选择覆盖
if ( temp > temperatures[i , j] )
temperatures[i , j] = temp;
}
}
}
}
}
给顶点color属性赋值
private void AddVertexColor( )
{
Color[] colors = new Color[meshFilter.mesh.colors.Length];
for ( int j = 0 ; j < vertical ; j++ )
{
for ( int i = 0 ; i < horizontal ; i++ )
colors[horizontal * j + i] = CalcColor(this.temperature[j , i]);
}
meshFilter.mesh.colors = colors;
}
生成网格赋予材质球
后续拓展
- 1.以上讲解了简单温度图的实现原理和代码编写,但是我们在项目不单单会使用到这类简单的功能,除了2D的温度图,我们可能会使用到三维的温度云图,温度云图又是如何实现的呢,我们在以后的文章再详细讲解吧。
- 2.温度图我们也可以拓展为UGUI组件,可只用在UGUI UI界面进行展示,到底该怎么编写,看过UGUI自定义组件文章的应该都很熟悉了,如果不懂,那你就点击下面的UGUI组件系列的链接去了解一下吧!
UGUI组件系列
Unity框架解读系列
分享地址(置顶目录包含所有组件的最新下载地址)
- Github :https://github.com/ll4080333/UnityCodes
- CSDN : http://blog.csdn.net/qq_29579137
- 博客专栏 : http://blog.csdn.net/column/details/16329.html
- 温度图组件下载地址 : http://download.csdn.net/download/qq_29579137/9968723
- QQ群 : 593906968 有什么不懂的可以加群咨询互相学习
如果你想了解UGUI的更多拓展组件,欢迎关注我的博客,我会持续更新,支持一下我这个博客新手,你的关注也会给予我更多的动力。如果以上文章对你有帮助,点个赞,让更多的人看到这篇文章,我们一起学习。如果有什么指点的地方欢迎在评论区留言,秒回复。