IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> Unity数据可视化 温度图效果(一) -> 正文阅读

[游戏开发]Unity数据可视化 温度图效果(一)

既然是使用Unity做可视化三维,那么基本的数据可视化效果还有要有的,之后几篇文章会讲解几种温度图效果的实现方案。

之前文章我们也讲了URP的好处,因为我们的所有效果都是在通用渲染管线下使用的。

效果视频:https://www.bilibili.com/video/BV1eW4y167bj?spm_id_from=333.337.search-card.all.click&vd_source=53e8eab748d74934d8848b24856aaffbhttps://www.bilibili.com/video/BV1eW4y167bj?spm_id_from=333.337.search-card.all.click&vd_source=53e8eab748d74934d8848b24856aaffb

基本逻辑讲解

效果是基于一个平面Mesh渲染的

每一个温度都保存了一个坐标位置和温度信息

在Shader中遍历所有坐标信息,计算当前渲染点的温度值

不同温度值形成不同的高度和颜色

创建Mesh

 public static Mesh CreatePlane(Vector2 scaleSize, Vector2 meshSize)
        {
            float perxlength = scaleSize.x / (meshSize.x - 1);
            float perzlength = scaleSize.y / (meshSize.y - 1);


            int totalcount = (int)meshSize.x * (int)meshSize.y;
            Vector3[] vertexs = new Vector3[totalcount];
            Vector3[] normals = new Vector3[totalcount];
            Vector2[] uvs = new Vector2[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] = Vector3.up;
                    uvs[index] = new Vector2(j / (meshSize.x - 1), i / (meshSize.y - 1));
                    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.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
            mesh.vertices = vertexs;
            mesh.normals = normals;
            mesh.triangles = triangles;
            mesh.uv = uvs;
            return mesh;
        }

创建Mesh的代码比较基础,因为创建的是一个规则的平面,这个需要注意的是Mesh的顶点数,这里需要设置一个合适的数,过大会影响性能,过小温度图的效果会有锯齿(WebGL平台,Windows平台有曲面细分)

温度数据保存

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace MY.TemperatureMap
{
    public class TemperatureMap : MonoBehaviour
    {  
        public TemperatureCoordinate _temperatureCoordinate;
        
        public List<Vector4> tempratureDatas = new List<Vector4>();
        
        public float maxRefrence = 0.5f;
        
        public float perTempHeight = 0.001f;
        
        public List<float> colorTempLine = new List<float> { 45, 20, 10, 0 };
        
        public List<Color> _colors = new List<Color> { new Color(1, 0.11f, 0, 1), new Color(1, 0.91f, 0.13f, 1), new Color(0.37f, 1, 0.21f , 1), new Color(0.16f, 0.24f, 1 , 0) };

        private Material _material;
        
        public MaterialPropertyBlock block;

        private MeshRenderer _meshrenderer;

        private void Start()
        {
            _material = GetComponent<MeshRenderer>().material;
            UpdateMaterialData(_material);
        }

        public void UpdateMaterialData(Material mat)
        {
            if (block == null)
                block = new MaterialPropertyBlock();
            SetMaterialBaseData(mat);
            UpdateTempraturePointDatas(mat);
            UpdateTempratureSplitLine(mat);
            if (_meshrenderer == null)
                _meshrenderer = GetComponent<MeshRenderer>();
            _meshrenderer.SetPropertyBlock(block);
        }

        private void SetMaterialBaseData(Material _material)
        {
            block.SetFloat("perTempHeight" , perTempHeight);
            block.SetFloat("maxRefrence" , maxRefrence);
        }

        private void UpdateTempraturePointDatas(Material _material)
        {
            block.SetInt("tempcount" , tempratureDatas.Count);
            if(tempratureDatas.Count == 0) return;
            if (_temperatureCoordinate == TemperatureCoordinate.Local)
            {
                List<Vector4> tempDatas = new List<Vector4>();
                foreach (var UPPER in tempratureDatas)
                {
                    Vector3 pos = transform.TransformPoint(UPPER);
                    tempDatas.Add(new Vector4(pos.x, pos.y, pos.z, UPPER.w));
                }
                block.SetVectorArray("tempData", tempDatas);
            }
            else
            {
                block.SetVectorArray("tempData", tempratureDatas);
            }
        }
        
        private void UpdateTempratureSplitLine(Material _material)
        {
            block.SetInt("colorcount" , colorTempLine.Count);
            if(colorTempLine.Count == 0) return;
            block.SetFloatArray("colorLine" , colorTempLine);
            
            List<Vector4> tempDatas = new List<Vector4>();
            foreach (var UPPER in _colors)
            {
                tempDatas.Add(UPPER);
            }
            block.SetVectorArray("_Colors" , tempDatas);
        }
    }

    
    [Serializable]
    public enum TemperatureCoordinate
    {
        Local,
        World
    }
}

这是完整C#代码,可以看到温度数据保存在一个Vector4中,前三位是坐标数据,第四位是温度数据。

颜色层级是可以配置的colorTempLine 保存了温度的分界线,_colors 保存了对应层级的颜色。两个数据的长度必须是一样的,一个层级对应一个颜色,颜色支持透明度。

温度值计算

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].z;

                     float distance = sqrt(deltax * deltax + deltay * deltay);
                     if(distance > maxRefrence)
                           continue;
                     float centerheight = perTempHeight * tempData[i].w;
                     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;
            }

这是shader部分的代码,GetHeight计算了当前点的高度

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

根据温度转换到对应层级的颜色,颜色需要有一定的融合,不然分界明显,效果就不好看了。

结尾

这篇文章做的是最基础的一种温度图效果,这种温度图也可以贴上一些贴图表现出更完美的效果(例如小颗粒点)。还有一些圆饼、柱状类的温度图之后的文章也会讲到。

整体的逻辑还是比较简单,如果看完文章还不会,点赞评论,我发你直接可以使用的插件。

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-07-05 23:42:25  更:2022-07-05 23:42:34 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 10:43:25-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码