Unity3d之将terrain转化成mesh

Posted 孤独の巡礼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity3d之将terrain转化成mesh相关的知识,希望对你有一定的参考价值。

Unity3d中,terrain还是比较耗的,为了优化性能,可能需要将terrain转化成mesh。

现提供一工具,思路是根据terrain高度图生成mesh等。

可参考: http://wiki.unity3d.com/index.php?title=TerrainObjExporter

转载请注明出处:

 http://www.cnblogs.com/jietian331/p/5831062.html

 

代码如下:

  1 using UnityEditor;
  2 using UnityEngine;
  3 
  4 public class TerrainToMeshConverter : ScriptableObject
  5 {
  6     [MenuItem("Custom/Convert terrain to mesh")]
  7     static void Init()
  8     {
  9         if (Selection.objects.Length <= 0)
 10         {
 11             Debug.Log("Selection.objects.Length <= 0");
 12             return;
 13         }
 14 
 15         var terrainObj = Selection.objects[0] as GameObject;
 16         if (terrainObj == null)
 17         {
 18             Debug.Log("terrainObj == null");
 19             return;
 20         }
 21 
 22         var terrain = terrainObj.GetComponent<Terrain>();
 23         if (terrain == null)
 24         {
 25             Debug.Log("terrain == null");
 26             return;
 27         }
 28 
 29         var terrainData = terrain.terrainData;
 30         if (terrainData == null)
 31         {
 32             Debug.Log("terrainData == null");
 33             return;
 34         }
 35 
 36         int vertexCountScale = 4;       // [dev] 将顶点数稀释 vertexCountScale*vertexCountScale 倍
 37         int w = terrainData.heightmapWidth;
 38         int h = terrainData.heightmapHeight;
 39         Vector3 size = terrainData.size;
 40         float[, ,] 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,每个顶点每个图片所占比重
 51         for (int i = 0; i < w; i++)
 52         {
 53             for (int j = 0; j < h; j++)
 54             {
 55                 int index = j * w + i;
 56                 float 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
 61                 int i2 = (int)(i * terrainData.alphamapWidth / (w - 1f));
 62                 int j2 = (int)(j * terrainData.alphamapHeight / (h - 1f));
 63                 i2 = Mathf.Min(terrainData.alphamapWidth - 1, i2);
 64                 j2 = Mathf.Min(terrainData.alphamapHeight - 1, j2);
 65                 var alpha0 = alphaMapData[j2, i2, 0];
 66                 var alpha1 = alphaMapData[j2, i2, 1];
 67                 var alpha2 = alphaMapData[j2, i2, 2];
 68                 var 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          */
 82         int[] triangles = new int[(w - 1) * (h - 1) * 6];
 83         int triangleIndex = 0;
 84         for (int i = 0; i < w - 1; i++)
 85         {
 86             for (int j = 0; j < h - 1; j++)
 87             {
 88                 int a = j * w + i;
 89                 int b = (j + 1) * w + i;
 90                 int c = (j + 1) * w + i + 1;
 91                 int 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         mesh.triangles = triangles;
107         mesh.tangents = alphasWeight;       // 将地形纹理的比重写入到切线中
108 
109         string transName = "[dev]MeshFromTerrainData";
110         var t = terrainObj.transform.parent.Find(transName);
111         if (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;
120         if (!mat)
121             mat = new Material(Shader.Find("Custom/Environment/TerrainSimple"));
122 
123         for (int i = 0; i < terrainData.splatPrototypes.Length; i++)
124         {
125             var sp = terrainData.splatPrototypes[i];
126             mat.SetTexture("_Texture" + i, sp.texture);
127         }
128 
129         t.parent = terrainObj.transform.parent;
130         t.position = terrainObj.transform.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 
27             struct appdata
28             {
29                 float4 vertex : POSITION;
30                 float2 uv : TEXCOORD0;
31                 float4 tangent : TANGENT;
32             };
33 
34             struct v2f
35             {
36                 float4 pos : SV_POSITION;
37                 float2 uv : TEXCOORD0;
38                 float4 weight : TEXCOORD1;
39             };
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;
47                 return 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;
57                 return 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 "UnityCG.cginc"
 32             #include "Lighting.cginc"
 33             #include "AutoLight.cginc"
 34 
 35             sampler2D _Texture0;
 36             sampler2D _Texture1;
 37             sampler2D _Texture2;
 38             sampler2D _Texture3;
 39 
 40             struct appdata
 41             {
 42                 float4 vertex : POSITION;
 43                 float2 uv : TEXCOORD0;
 44                 float4 tangent : TANGENT;
 45                 float3 normal : NORMAL;
 46             };
 47 
 48             struct 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;
 65                 o.worldPos = mul(unity_ObjectToWorld, v.vertex);
 66                 o.worldNormal = UnityObjectToWorldNormal(v.normal);
 67                 TRANSFER_SHADOW(o);
 68                 UNITY_TRANSFER_FOG(o, o.pos);
 69                 return 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 = tex.rgb;
 81 
 82                 fixed3 ambient = albedo * UNITY_LIGHTMODEL_AMBIENT.rgb;
 83 
 84                 float3 worldLight = normalize(UnityWorldSpaceLightDir(i.worldPos));
 85                 float halfLambert = dot(worldLight, i.worldNormal) * 0.5 + 0.5;
 86                 fixed3 diffuse = albedo * _LightColor0.rgb * halfLambert;
 87 
 88                 float3 worldView = normalize(UnityWorldSpaceViewDir(i.worldPos));
 89                 float3 halfDir = normalize(worldView + worldLight);
 90                 fixed3 specular = albedo * _LightColor0.rgb * 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 
 96                 return 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 "UnityCG.cginc"
116             #include "Lighting.cginc"
117             #include "AutoLight.cginc"
118 
119             sampler2D _Texture0;
120             sampler2D _Texture1;
121             sampler2D _Texture2;
122             sampler2D _Texture3;
123 
124             struct appdata
125             {
126                 float4 vertex : POSITION;
127                 float2 uv : TEXCOORD0;
128                 float4 tangent : TANGENT;
129                 float3 normal : NORMAL;
130             };
131 
132             struct 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 = UnityObjectToWorldNormal(v.normal);
150                 TRANSFER_SHADOW(o);
151                 return 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 = tex.rgb;
163 
164                 float3 worldLight = normalize(UnityWorldSpaceLightDir(i.worldPos));
165                 float halfLambert = dot(worldLight, i.worldNormal) * 0.5 + 0.5;
166                 fixed3 diffuse = albedo * _LightColor0.rgb * halfLambert;
167 
168                 float3 worldView = normalize(UnityWorldSpaceViewDir(i.worldPos));
169                 float3 halfDir = normalize(worldView + worldLight);
170                 fixed3 specular = albedo * _LightColor0.rgb * 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 
175                 return col;
176             }
177 
178             ENDCG
179         }
180     }
181 
182     Fallback "Diffuse"
183 }
Custom/Environment/LightedTerrain

 

光照效果如下:

 

以上是关于Unity3d之将terrain转化成mesh的主要内容,如果未能解决你的问题,请参考以下文章

Unity3D如何把Mesh顶点转化到世界坐标系

cesium高程tif数据转化成terrain

动态加载烘培贴图与Terrain转mesh

动态加载烘培贴图与Terrain转mesh

gson之将对象转化成json字符串的方法

Unity3D地形Terrain