Unity3d之将terrain转化成mesh
Unity3d中,terrain还是⽐较耗的,为了优化性能,可能需要将terrain转化成mesh。
现提供⼀⼯具,思路是根据terrain⾼度图⽣成mesh等。
转载请注明出处:
代码如下:
1using UnityEditor;
2using UnityEngine;
3
4public class TerrainToMeshConverter : ScriptableObject
5 {
6 [MenuItem("Custom/Convert terrain to mesh")]
7static void Init()
8 {
9if (Selection.objects.Length <= 0)
10 {
11 Debug.Log("Selection.objects.Length <= 0");
12return;
13 }
14
15var terrainObj = Selection.objects[0] as GameObject;
16if (terrainObj == null)
17 {
18 Debug.Log("terrainObj == null");
19return;
20 }
21
22var terrain = terrainObj.GetComponent<Terrain>();
23if (terrain == null)
24 {
25 Debug.Log("terrain == null");
26return;
27 }
28
29var terrainData = ainData;
30if (terrainData == null)
31 {
32 Debug.Log("terrainData == null");
33return;
34 }
35
36int vertexCountScale = 4; // [dev] 将顶点数稀释 vertexCountScale*vertexCountScale 倍
37int w = terrainData.heightmapWidth;
38int h = terrainData.heightmapHeight;
39 Vector3 size = terrainData.size;
40float[, ,] alphaMapData = terrainData.GetAlphamaps(0, 0, terrainData.alphamapWidth, terrainData.alphamapHeight);
41 Vector3 meshScale = new Vector3(size.x / (w - 1f) * vertexCountScale, 1, size.z / (h - 1f) * vertexCountScale);
42 Vector2 uvScale = new Vector2(1f / (w - 1f), 1f / (h - 1f)) * vertexCountScale * (size.x / terrainData.splatPrototypes[0].tileSize.x); // [dev] 此处有问题,若每个图⽚⼤⼩不⼀,则出问题。⽇后改善 43
44 w = (w - 1) / vertexCountScale + 1;
45 h = (h - 1) / vertexCountScale + 1;
46 Vector3[] vertices = new Vector3[w * h];
47 Vector2[] uvs = new Vector2[w * h];
48 Vector4[] alphasWeight = new Vector4[w * h]; // [dev] 只⽀持4张图⽚
49
50// 顶点,uv,每个顶点每个图⽚所占⽐重
51for (int i = 0; i < w; i++)
52 {
53for (int j = 0; j < h; j++)
54 {
55int index = j * w + i;
56float z = terrainData.GetHeight(i * vertexCountScale, j * vertexCountScale);
57 vertices[index] = Vector3.Scale(new Vector3(i, z, j), meshScale);
58 uvs[index] = Vector2.Scale(new Vector2(i, j), uvScale);
59
60// alpha map
61int i2 = (int)(i * terrainData.alphamapWidth / (w - 1f));
62int j2 = (int)(j * terrainData.alphamapHeight / (h - 1f));
63 i2 = Mathf.Min(terrainData.alphamapWidth - 1, i2);
64 j2 = Mathf.Min(terrainData.alphamapHeight - 1, j2);
65var alpha0 = alphaMapData[j2, i2, 0];
66var alpha1 = alphaMapData[j2, i2, 1];
67var alpha2 = alphaMapData[j2, i2, 2];
68var alpha3 = alphaMapData[j2, i2, 3];
69 alphasWeight[index] = new Vector4(alpha0, alpha1, alpha2, alpha3);
70 }
71 }
72
73/*
74 * 三⾓形
75 * b c
76 * *******
77 * * * *
78 * * * *
79 * *******
80 * a d
81*/
82int[] triangles = new int[(w - 1) * (h - 1) * 6];
83int triangleIndex = 0;
84for (int i = 0; i < w - 1; i++)
85 {
86for (int j = 0; j < h - 1; j++)
88int a = j * w + i;
89int b = (j + 1) * w + i;
90int c = (j + 1) * w + i + 1;
91int d = j * w + i + 1;
92
93 triangles[triangleIndex++] = a;
94 triangles[triangleIndex++] = b;
95 triangles[triangleIndex++] = c;
96
97 triangles[triangleIndex++] = a;
98 triangles[triangleIndex++] = c;
99 triangles[triangleIndex++] = d;
100 }
101 }
102
103 Mesh mesh = new Mesh();
104 mesh.vertices = vertices;
105 mesh.uv = uvs;
106 iangles = triangles;
107 mesh.tangents = alphasWeight; // 将地形纹理的⽐重写⼊到切线中
108
109string transName = "[dev]MeshFromTerrainData";
110var t = ansform.parent.Find(transName);
111if (t == null)
112 {
113 GameObject go = new GameObject(transName, typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshCollider)); 114 t = go.transform;
115 }
116
117// 地形渲染
118 MeshRenderer mr = t.GetComponent<MeshRenderer>();
119 Material mat = mr.sharedMaterial;
120if (!mat)
121 mat = new Material(Shader.Find("Custom/Environment/TerrainSimple"));
122
123for (int i = 0; i < terrainData.splatPrototypes.Length; i++)
124 {
125var sp = terrainData.splatPrototypes[i];
126 mat.SetTexture("_Texture" + i, sp.texture);
127 }
128
129 t.parent = ansform.parent;
130 t.position = ansform.position;
131 t.gameObject.layer = terrainObj.layer;
132 t.GetComponent<MeshFilter>().sharedMesh = mesh;
133 t.GetComponent<MeshCollider>().sharedMesh = mesh;
134 mr.sharedMaterial = mat;
135
136 t.gameObject.SetActive(true);
137 terrainObj.SetActive(false);
138
139 Debug.Log("Convert terrain to mesh finished!");
140 }
141 }
TerrainToMeshConverter
渲染地形的shader如下(不⽀持光照):
1 Shader "Custom/Environment/TerrainSimple"
2 {
3 Properties
4 {
5 _Texture0 ("Texture 1", 2D) = "white" {}
6 _Texture1 ("Texture 2", 2D) = "white" {}
7 _Texture2 ("Texture 3", 2D) = "white" {}
8 _Texture3 ("Texture 4", 2D) = "white" {}
9 }
10
11 SubShader
12 {
13 Tags { "RenderType" = "Opaque" }
14 LOD 200
15
16 Pass
17 {
18 CGPROGRAM
19#pragma vertex vert
20#pragma fragment frag
21
22 sampler2D _Texture0;
23 sampler2D _Texture1;
24 sampler2D _Texture2;
25 sampler2D _Texture3;
26
27struct appdata
28 {
29 float4 vertex : POSITION;
30 float2 uv : TEXCOORD0;
31 float4 tangent : TANGENT;
32 };
33
34struct v2f
35 {
36 float4 pos : SV_POSITION;
37 float2 uv : TEXCOORD0;
38 float4 weight : TEXCOORD1;
40
41 v2f vert(appdata v)
42 {
43 v2f o;
44 o.pos = UnityObjectToClipPos(v.vertex);
45 o.weight = v.tangent;
46 o.uv = v.uv;
47return o;
48 }
49
50 fixed4 frag(v2f i) : SV_TARGET
51 {
52 fixed4 t0 = tex2D(_Texture0, i.uv);
53 fixed4 t1 = tex2D(_Texture1, i.uv);
54 fixed4 t2 = tex2D(_Texture2, i.uv);
55 fixed4 t3 = tex2D(_Texture3, i.uv);
56 fixed4 tex = t0 * i.weight.x + t1 * i.weight.y + t2 * i.weight.z + t3 * i.weight.w; 57return tex;
58 }
59
60 ENDCG
61 }
62 }
63
64 Fallback "Diffuse"
65 }
Custom/Environment/TerrainSimple
⽣成的mesh与原terrain对⽐如下,左边为mesh,右边为terrain:
另提供⼀⽀持光照的地形shader:
1// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' 2
3 Shader "Custom/Environment/LightedTerrain"
4 {
5 Properties
6 {
7 _Texture0 ("Texture 1", 2D) = "white" {}
8 _Texture1 ("Texture 2", 2D) = "white" {}
9 _Texture2 ("Texture 3", 2D) = "white" {}
10 _Texture3 ("Texture 4", 2D) = "white" {}
11 }
12
13 SubShader
14 {
15 Tags { "RenderType" = "Opaque" }
16 LOD 200
17
18 Pass
19 {
20 Tags
21 {
22"LightMode" = "ForwardBase"
23 }
24
25 CGPROGRAM
26#pragma vertex vert
27#pragma fragment frag
28#pragma multi_compile_fwdbase
29#pragma multi_compile_fog
30
31 #include "inc"
32 #include "inc"
33 #include "inc"
34
35 sampler2D _Texture0;
36 sampler2D _Texture1;
37 sampler2D _Texture2;
38 sampler2D _Texture3;
39
40struct appdata
41 {
42 float4 vertex : POSITION;
43 float2 uv : TEXCOORD0;
44 float4 tangent : TANGENT;
45 float3 normal : NORMAL;
46 };
47
48struct v2f
49 {
50 float4 pos : SV_POSITION;
51 float2 uv : TEXCOORD0;
52 float4 weight : TEXCOORD1;
53 float3 worldPos : TEXCOORD2;
54 float3 worldNormal : TEXCOORD3;
55 SHADOW_COORDS(4)
56 UNITY_FOG_COORDS(5)
57 };
58
59 v2f vert(appdata v)
60 {
61 v2f o;
62 o.pos = UnityObjectToClipPos(v.vertex);
63 o.weight = v.tangent;
64 o.uv = v.uv;
transform和convert的区别65 o.worldPos = mul(unity_ObjectToWorld, v.vertex);
66 o.worldNormal = al);
67 TRANSFER_SHADOW(o);
68 UNITY_TRANSFER_FOG(o, o.pos);
69return o;
70 }
71
72 fixed4 frag(v2f i) : SV_TARGET
73 {
74 fixed4 t0 = tex2D(_Texture0, i.uv);
75 fixed4 t1 = tex2D(_Texture1, i.uv);
76 fixed4 t2 = tex2D(_Texture2, i.uv);
77 fixed4 t3 = tex2D(_Texture3, i.uv);
78 fixed4 tex = t0 * i.weight.x + t1 * i.weight.y + t2 * i.weight.z + t3 * i.weight.w;
79
80 fixed3 albedo = b;
81
82 fixed3 ambient = albedo * UNITY_b;
83
84 float3 worldLight = normalize(UnityWorldSpaceLightDir(i.worldPos));
85float halfLambert = dot(worldLight, i.worldNormal) * 0.5 + 0.5;
86 fixed3 diffuse = albedo * _b * halfLambert;
87
88 float3 worldView = normalize(UnityWorldSpaceViewDir(i.worldPos));
89 float3 halfDir = normalize(worldView + worldLight);
90 fixed3 specular = albedo * _b * max(dot(halfDir, i.worldNormal), 0); 91
92 UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
93 fixed4 col = fixed4(ambient + (diffuse + specular) * atten, tex.a);
94 UNITY_APPLY_FOG(i.fogCoord, col);
95
96return col;
97 }
98
99 ENDCG
100 }
101
102 Pass
103 {
104 Tags
105 {
106"LightMode" = "ForwardAdd"
107 }
108 Blend One One
109
110 CGPROGRAM
111#pragma vertex vert
112#pragma fragment frag
113#pragma multi_compile_fwdadd
114
115 #include "inc"
116 #include "inc"
117 #include "inc"
118
119 sampler2D _Texture0;
120 sampler2D _Texture1;
121 sampler2D _Texture2;
122 sampler2D _Texture3;
123
124struct appdata
125 {
126 float4 vertex : POSITION;
127 float2 uv : TEXCOORD0;
128 float4 tangent : TANGENT;
129 float3 normal : NORMAL;
130 };
131
132struct v2f
133 {
134 float4 pos : SV_POSITION;
135 float2 uv : TEXCOORD0;
136 float4 weight : TEXCOORD1;
137 float3 worldPos : TEXCOORD2;
138 float3 worldNormal : TEXCOORD3;
139 SHADOW_COORDS(4)
140 };
141
142 v2f vert(appdata v)
143 {
144 v2f o;
145 o.pos = UnityObjectToClipPos(v.vertex);
146 o.weight = v.tangent;
147 o.uv = v.uv;
148 o.worldPos = mul(unity_ObjectToWorld, v.vertex);
149 o.worldNormal = al);
150 TRANSFER_SHADOW(o);
151return o;
152 }
153
154 fixed4 frag(v2f i) : SV_TARGET
155 {
156 fixed4 t0 = tex2D(_Texture0, i.uv);
157 fixed4 t1 = tex2D(_Texture1, i.uv);
158 fixed4 t2 = tex2D(_Texture2, i.uv);
159 fixed4 t3 = tex2D(_Texture3, i.uv);
160 fixed4 tex = t0 * i.weight.x + t1 * i.weight.y + t2 * i.weight.z + t3 * i.weight.w; 161
162 fixed3 albedo = b;
163
164 float3 worldLight = normalize(UnityWorldSpaceLightDir(i.worldPos));
165float halfLambert = dot(worldLight, i.worldNormal) * 0.5 + 0.5;
166 fixed3 diffuse = albedo * _b * halfLambert;
167
168 float3 worldView = normalize(UnityWorldSpaceViewDir(i.worldPos));
169 float3 halfDir = normalize(worldView + worldLight);
170 fixed3 specular = albedo * _b * max(dot(halfDir, i.worldNormal), 0); 171
172 UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
173 fixed4 col = fixed4((diffuse + specular ) * atten, tex.a);
174
175return col;
176 }
177
178 ENDCG
179 }
180 }
181
182 Fallback "Diffuse"
183 }
Custom/Environment/LightedTerrain
光照效果如下:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论