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 <= )
  10. {
  11. Debug.Log("Selection.objects.Length <= 0");
  12. return;
  13. }
  14.  
  15. var terrainObj = Selection.objects[] 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 = ; // [dev] 将顶点数稀释 vertexCountScale*vertexCountScale 倍
  37. int w = terrainData.heightmapWidth;
  38. int h = terrainData.heightmapHeight;
  39. Vector3 size = terrainData.size;
  40. float[, ,] alphaMapData = terrainData.GetAlphamaps(, , terrainData.alphamapWidth, terrainData.alphamapHeight);
  41. Vector3 meshScale = new Vector3(size.x / (w - 1f) * vertexCountScale, , size.z / (h - 1f) * vertexCountScale);
  42. Vector2 uvScale = new Vector2(1f / (w - 1f), 1f / (h - 1f)) * vertexCountScale * (size.x / terrainData.splatPrototypes[].tileSize.x); // [dev] 此处有问题,若每个图片大小不一,则出问题。日后改善
  43.  
  44. w = (w - ) / vertexCountScale + ;
  45. h = (h - ) / vertexCountScale + ;
  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 = ; i < w; i++)
  52. {
  53. for (int j = ; 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 - , i2);
  64. j2 = Mathf.Min(terrainData.alphamapHeight - , j2);
  65. var alpha0 = alphaMapData[j2, i2, ];
  66. var alpha1 = alphaMapData[j2, i2, ];
  67. var alpha2 = alphaMapData[j2, i2, ];
  68. var alpha3 = alphaMapData[j2, i2, ];
  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 - ) * (h - ) * ];
  83. int triangleIndex = ;
  84. for (int i = ; i < w - ; i++)
  85. {
  86. for (int j = ; j < h - ; j++)
  87. {
  88. int a = j * w + i;
  89. int b = (j + ) * w + i;
  90. int c = (j + ) * w + i + ;
  91. int d = j * w + i + ;
  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 = ; 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
  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
  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()
  56. UNITY_FOG_COORDS()
  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), );
  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()
  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), );
  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的更多相关文章

  1. 【Unity3D】利用Shader以及更改Mesh实现2D游戏的动态阴影效果

    最近看到一个非常有趣的益智小游戏,是一个盗贼进入房子偷东西的, 其实这种游戏市面上已经很多了,吸引我的是那个类似手电筒的效果, 主角走到哪里,光就到哪里,被挡住的地方还有阴影.有点类似策略游戏里的战争 ...

  2. [原]Unity3D深入浅出 - 导航网格自动寻路(Navigation Mesh)

    NavMesh(导航网格)是3D游戏世界中用于实现动态物体自动寻路的一种技术,将游戏中复杂的结构组织关系简化为带有一定信息的网格,在这些网格的基础上通过一系列的计算来实现自动寻路..导航时,只需要给导 ...

  3. Unity3D学习笔记——游戏组件之Mesh(网格组件)

    Mesh:网格组件.主要用于设置外形和外表. Mesh Filter:网格过滤器.就是为游戏对象添加一个外形. 例:设置外形为Sphere  如果获取的网格拥有蒙皮信患,Unity将自动创建一个skn ...

  4. Unity3d修炼之路:用Mesh绘制一个Cube

    #pragma strict function Awake(){ var pMeshFilter : MeshFilter = gameObject.AddComponent(typeof(MeshF ...

  5. mesh合并

    [风宇冲]Unity3D性能优化:DrawCall优化 (2013-03-05 15:39:27) 转载▼ 标签: it unity unity3d unity3d教程 分类: Unity3d之优化 ...

  6. Axiom3D:手动创建ManualObject与Mesh,以及如何使用Cg着色器语言

    在开始正文前,先说下Axiom3D里遇到的二个BUG. 1.在启动axiom生成的程序中,我发现输出里总是有一些如"billboard_type","billboard_ ...

  7. three.js 根据png生成heightmap

    Three.js: render real world terrain from heightmap using open data By jos.dirksen on Tue, 07/17/2012 ...

  8. [转]Cryengine渲染引擎剖析

    转篇Napoleon314 大牛的分析,排版好乱,见谅,耐心读,这是个好东西,注意看他自己的实现,是个技术狂人啊,Ogre焕发次时代的光芒啊~~~努力 ------------------------ ...

  9. Unity3D根据游戏的发展Terrain Toolkit地形生产

     今天我们继续给我Unity3D游戏开发系列.今天我们来通过Terrain Toolkit为了使地形. 虽然Unity3D它为我们提供了一个地形渲染工具,我们发现,这个地形绘制工具并不能满足我们的 ...

随机推荐

  1. ACdream 1732

    input 样例个数T           <=10000 每个样例一个n(2<=n<=10^8) output lcm(1,2,...,n)%2^32 Sample Input 5 ...

  2. [笔记]The Linux command line

    Notes on The Linux Command Line (by W. E. Shotts Jr.) edited by Gopher 感觉博客园是不是搞了什么CSS在里头--在博客园显示效果挺 ...

  3. CSS3入门

    CSS3 w3cschools css3  MDN英文  MDN中文 CSS3 is the latest evolution of the Cascading Style Sheets langua ...

  4. 字符串ID转换成字符串名字

    select  U.CnName+','  from f_splitstr('1828,1055333,1,1035681,752,494,22549,219,23860,478,23453,677, ...

  5. Applet签名

    applet签名 1.生成密匙库 keytool -genkey -keystore mytest.store -alias mytest -validity 365 -keystore 密匙库 -a ...

  6. 利用LinkedList实现洗牌功能

    分2步: 1.生成扑克牌. 2.洗牌. package com.dongbin.collection; import java.util.LinkedList; import java.util.Ra ...

  7. 使用PHP连接redis后,timeout连接太多的解决方案

    这个问题,大家在使用php redis之后肯定都会遇到.所以本菜本着虚心求教的原则,又在网上四处求教.得到的答案,无非是以下两种: 1.redis没有主动close. 事后发现,这个答案纯属以讹传讹, ...

  8. Python统计栏目页面数量

    主要为了装个B,统计栏目页面数量时候用的,多线程基本照抄 http://www.cnblogs.com/fnng/p/3670789.html 关于对SEO有什么用处...我觉得...仅对本人有用,P ...

  9. android项目实战 --ListView 头部ViewPager广告轮询图效果

    看开源框架:https://github.com/tianshaojie/AndroidFine,里面有如下效果,特记录学习下,以后项目中用也好能够立刻想起来.   如上面所示,是常见项目中的图片轮训 ...

  10. Linux下安装vnstat流量统计

    1. 下载安装 cd /data/software wget http://humdi.net/vnstat/vnstat-1.11.tar.gz tar zxf vnstat-1.11.tar.gz ...