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小时内删除。