unity 制作3D等温图

本文介绍了一种使用Unity创建3D等温图的方法,包括动态生成mesh、利用贝塞尔曲线平滑mesh以及通过顶点颜色赋予mesh温度变化效果。此外,还详细介绍了如何制作渐变纹理和应用自定义shader来增强3D模型的真实感。
摘要由CSDN通过智能技术生成

3D等温图的制作过程

思路1

动态生成mesh

动态生成texture2D

将texture2D通过uv赋值

思路2

动态生成mesh

通过赋值mesh.color赋值颜色

思路2过于复杂,对于我有点难度,选择1

mesh生成通过贝塞尔曲线使它更加光滑

实现代码如下

private void CreatMeshWithValue() {

		BezierTerrain bezier = new BezierTerrain();
                //va,vb....为vector3[]数组,bezier.CreatPath方法会返回一个贝塞尔曲线的路径
                object[] allV = new object[]
		{
			bezier.CreatPath(va,6),
			bezier.CreatPath(vb,6),
			bezier.CreatPath(vc,6),
			bezier.CreatPath(vd,6),
			bezier.CreatPath(ve,6),
			bezier.CreatPath(vf,6),
			bezier.CreatPath(vg,6)
		};
		float MaxMinValue = 12f;

		List<object> allC = new List<object>();
		foreach (Vector3[] v in allV)
		{
			List<Color> colorArr = new List<Color>();
			foreach (Vector3 item in v)
			{
				float value = (item.y / MaxMinValue) * 4 * 255;

				Color color;
				if (0f <= value && value < 255)
				{
					color = new Color(0f, value, 255f);
				}
				else if (value >= 255f && value < 510f)
				{
					color = new Color(0, 255f, 255f - (value - 255f));
				}
				else if (value >= 510f && value < 765f)
				{
					color = new Color((value - 510f), 255f, 0f);
				}
				else
				{
					color = new Color(255, 255f - (value - 765f), 0f);
				}
				colorArr.Add(color);
			}
			allC.Add(colorArr.ToArray());
		}
		object[] a = allC.ToArray();
		MeshWithVector3sColors(allV, allC.ToArray());
	}
	
	//mesh
	void MeshWithVector3sColors(object[] allV,object[] allC) {

		MeshFilter meshFilter = this.gameObject.GetComponent<MeshFilter>();
		Mesh mesh = new Mesh();
		mesh.name = "ColorMesh";

		//顶点数量
		int verticesCount = allV.Length * (allV[0] as Vector3[]).Length;
		Vector3[] vertices = new Vector3[verticesCount];
		
		//三角形数量
		int triangles_count = (allV.Length - 1) * ((allV[0] as Vector3[]).Length - 1 ) * 2 ;
		//三角形顶点ID
		int[] triangles = new int[triangles_count * 3];
		//
		Color[] colorCount = new Color[verticesCount];
		int index_v = 0;
		//Vector2[] uvs = new Vector2[verticesCount];

		//vertice color
		for (int i = 0; i < allV.Length; i++) {
			Vector3[] vi = allV[i] as Vector3[];
			for (int j = 0; j < (allV[i] as Vector3[]).Length; j++) {
				vertices[index_v] = vi[j];
				Color color = (allC[i] as Color[])[j];
				colorCount[index_v] = new Color(color.r / 255f,color.g / 255f,color.b / 255f,1f);
				index_v++;
			}
		}
		
		//triangles
		int index_t = 0;
		for (int i = 0; i < allV.Length - 1; i++)
		{
			Vector3[] vi = allV[i] as Vector3[];
			int nW = allV.Length;
			int nH = vi.Length;
			for (int j = 0; j < vi.Length - 1; j++)
			{
				triangles[index_t++] = i * vi.Length + j;
				triangles[index_t++] = (i + 1) * vi.Length + j;
				triangles[index_t++] = (i + 1) * vi.Length + j + 1;
				triangles[index_t++] = i * vi.Length + j;
				triangles[index_t++] = (i + 1) * vi.Length + j + 1;
				triangles[index_t++] = i * vi.Length + j + 1;
			}
		}
		//uv贴图与veritces重合便可以将制作的贴图贴上,但是个点的比例要与mesh三角形比例相同,否则无法贴上
		//List<Vector2> uvV2 = new List<Vector2>();
		//for (int i = 0; i < allV.Length; i++)
		//{
		//	for (int j = 0; j < (allV[i] as Vector3[]).Length; j++)
		//	{
		//		Vector2 v = new Vector2((float)j * (1f / (float)((allV[i] as Vector3[]).Length - 1)), (float)i * (1f / ((float)allV.Length - 1)));
		//		uvV2.Add(v);
		//		Debug.Log(v.x + " " + v.y);
		//		countUV++;
		//	}
		//}
		//mesh.uv = new Vector2[] { new Vector2 (0,0),new Vector2(0,1),new Vector2(1,1) };

		mesh.vertices = vertices;
		mesh.triangles = triangles;
		mesh.colors = colorCount;
		mesh.RecalculateNormals();
		meshFilter.mesh = mesh;
	}

使用shader,具体的参考

http://blog.csdn.net/qq_29579137/article/details/77854504

参考这个博主的文章,使用里面的shader,当然我还学着写了一个高光的shader,更有立体感

Shader "Volume13/4.Specular"  
{  
    //------------------------------------【属性值】------------------------------------  
    Properties  
    {  
        //主颜色  
        _Color("Main Color", Color) = (1, 1, 1, 1)  
        //镜面反射颜色  
        _SpecColor("Specular Color", Color) = (1, 1, 1, 1)  
        //镜面反射光泽度  
        _SpecShininess("Specular Shininess", Range(1.0, 100.0)) = 10.0  
    }  
  
    //------------------------------------【唯一的子着色器】------------------------------------  
    SubShader  
    {  
        //渲染类型设置:不透明  
        Tags{ "RenderType" = "Opaque" }  
        LOD 200
  
        //--------------------------------唯一的通道-------------------------------  
        Pass  
        {  
		    
            //光照模型ForwardBase  
            Tags{ "LightMode" = "ForwardBase" }
			Cull OFF
            //===========开启CG着色器语言编写模块===========  
            CGPROGRAM  
  
            //编译指令:告知编译器顶点和片段着色函数的名称  
            #pragma vertex vert  
            #pragma fragment frag  
  
            //顶点着色器输入结构  
            struct appdata  
            {  
                float4 vertex : POSITION;//顶点位置  
                float3 normal : NORMAL;//法线向量坐标  

				fixed4 color :COLOR;
            };  
  
            //顶点着色器输出结构  
            struct v2f  
            {  
                float4 pos : SV_POSITION;//像素位置  
                float3 normal : NORMAL;//法线向量坐标  
                float4 posWorld : TEXCOORD0;//在世界空间中的坐标位置  

				fixed4 color :COLOR;
            };  
  
  
            //变量的声明  
            float4 _LightColor0;  
            float4 _Color;  
            float4 _SpecColor;  
            float _SpecShininess;  
  
            //--------------------------------【顶点着色函数】-----------------------------  
            // 输入:顶点输入结构体  
            // 输出:顶点输出结构体  
            //---------------------------------------------------------------------------------  
            //顶点着色函数  
            v2f vert(appdata IN)  
            {  
                //【1】声明一个输出结构对象  
                v2f OUT;  
  
                //【2】填充此输出结构  
                //输出的顶点位置为模型视图投影矩阵乘以顶点位置,也就是将三维空间中的坐标投影到了二维窗口  
                OUT.pos = mul(UNITY_MATRIX_MVP, IN.vertex);  
                //获得顶点在世界空间中的位置坐标  
                OUT.posWorld = mul(unity_ObjectToWorld, IN.vertex);  
                //获取顶点在世界空间中的法线向量坐标  
                OUT.normal = mul(float4(IN.normal, 0.0), unity_WorldToObject).xyz;  
                OUT.color = IN.color;
                //【3】返回此输出结构对象  
                return OUT;  
            }  
  
            //--------------------------------【片段着色函数】-----------------------------  
            // 输入:顶点输出结构体  
            // 输出:float4型的像素颜色值  
            //---------------------------------------------------------------------------------  
            fixed4 frag(v2f IN) : COLOR  
            {  
                //【1】先准备好需要的参数  
                //获取法线的方向  
                float3 normalDirection = normalize(IN.normal);  
                //获取入射光线的方向  
                float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);  
                //获取视角方向  
                float3 viewDirection = normalize(_WorldSpaceCameraPos - IN.posWorld.xyz);  
  
                //【2】计算出漫反射颜色值  Diffuse=LightColor * MainColor * max(0,dot(N,L))  
                float3 diffuse = _LightColor0.rgb * IN.color * max(0.0, dot(normalDirection, lightDirection));  
  
                //【3】计算镜面反射颜色值   
                float3 specular;  
                //若是法线方向和入射光方向大于180度,镜面反射值为0  
                if (dot(normalDirection, lightDirection) < 0.0)  
                {  
                    specular = float3(0.0, 0.0, 0.0);  
                }  
                //否则,根据公式进行计算 Specular =LightColor * SpecColor *pow(max(0,dot(R,V)),Shiness),R=reflect(-L,N)  
                else  
                {  
                    float3 reflectDirection = reflect(-lightDirection, normalDirection);  
                        specular = _LightColor0.rgb * _SpecColor.rgb * pow(max(0.0, dot(reflectDirection, viewDirection)), _SpecShininess);  
                }  
  
                //【4】合并漫反射、镜面反射、环境光的颜色值  
                float4 diffuseSpecularAmbient = float4(diffuse, 1.0) + float4(specular, 1.0) + UNITY_LIGHTMODEL_AMBIENT;  
  
                //【5】将漫反射-镜面反射-环境光的颜色值返回  
                return diffuseSpecularAmbient;  
            }  
  
            //===========结束CG着色器语言编写模块===========  
            ENDCG  
        }  
    }  
}
这样输入几个vector3[]路径,就可以返回一个3D的等温图了

贝塞尔曲线类的代码是可以参考我过去的博文

http://blog.csdn.net/qq_37240033/article/details/77945599


学习过程中还学会了制作渐变texture2D

具体代码是

        Texture2D allTexture(object[] allC,int width,int height)
	{
		proceduralTexture = new Texture2D(width * ((allC[0] as Color[]).Length - 1), (allC.Length - 1) * height);
		int j = 0;
		for (int color_x = 0; color_x < allC.Length - 1; color_x++)
		{
			int i = 0;
			Color[] color_0 = allC[color_x] as Color[];
			Color[] color_1 = allC[color_x + 1] as Color[];
			for (int color_y = 0; color_y < (allC[color_x] as Color[]).Length - 1; color_y++)
			{
				CreatMeshItemTexture(color_0[color_y], color_0[color_y + 1], color_1[color_y], color_1[color_y + 1], width, height, i, j);
				i++;
			}
			j++;
		}
		proceduralTexture.Apply();
		return proceduralTexture;
	}

	public void CreatMeshItemTexture(Color a1, Color a2, Color a3, Color a4, int width, int height, int coutWidth, int coutHeight)
	{
		for (int y = 0; y < height; y++)
		{
			float dr_13 = (a3.r - a1.r) / height;
			float dg_13 = (a3.g - a1.g) / height;
			float db_13 = (a3.b - a1.b) / height;
			Color dx0 = new Color(dr_13 * y + a1.r, dg_13 * y + a1.g, db_13 * y + a1.b);

			float dr_24 = (a4.r - a2.r) / height;
			float dg_24 = (a4.g - a2.g) / height;
			float db_24 = (a4.b - a2.b) / height;
			Color dx1 = new Color(dr_24 * y + a2.r, dg_24 * y + a2.g, db_24 * y + a2.b);
			for (int x = 0; x < width; x++)
			{
				float dr = (dx1.r - dx0.r) / width;
				float dg = (dx1.g - dx0.g) / width;
				float db = (dx1.b - dx0.b) / width;
				Color pixeColor = new Color((dr * x + dx0.r) / 255f , (dg * x + dx0.g) / 255f, (db * x + dx0.b) / 255f);
				proceduralTexture.SetPixel(x + coutWidth * width, y + coutHeight * height, pixeColor);

			}
		}
	}


最终效果



参考了

http://blog.csdn.net/qq_29579137/article/details/77854504

http://blog.csdn.net/nanggong/article/details/54311090


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值