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