Unity3d之将terrain转化成mesh

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

现提供一工具,思路是根据terrain高度图生成mesh等,可参考: http://wiki.unity3d.com/index.php?title=TerrainObjExporter

代码还有诸多问题,如下:

  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             DevDebug.Log("Selection.objects.Length <= 0");
 12             return;
 13         }
 14
 15         var terrainObj = Selection.objects[0] as GameObject;
 16         if (terrainObj == null)
 17         {
 18             DevDebug.Log("terrainObj == null");
 19             return;
 20         }
 21
 22         var terrain = terrainObj.GetComponent<Terrain>();
 23         if (terrain == null)
 24         {
 25             DevDebug.Log("terrain == null");
 26             return;
 27         }
 28
 29         var terrainData = terrain.terrainData;
 30         if (terrainData == null)
 31         {
 32             DevDebug.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         mesh.Optimize();
109
110         // 地形渲染  [dev] 目前不支持光照,有待改善
111         var mat = new Material(Shader.Find("Custom/TerrainDiffuse"));
112         for (int i = 0; i < terrainData.splatPrototypes.Length; i++)
113         {
114             var sp = terrainData.splatPrototypes[i];
115             mat.SetTexture("_Texture" + i, sp.texture);
116         }
117
118         string transName = "[dev]MeshFromTerrainData";
119         var t = terrainObj.transform.parent.Find(transName);
120         if (t == null)
121         {
122             GameObject go = new GameObject(transName, typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshCollider));
123             t = go.transform;
124         }
125
126         t.parent = terrainObj.transform.parent;
127         t.position = terrainObj.transform.position;
128         t.gameObject.layer = terrainObj.layer;
129         t.GetComponent<MeshFilter>().sharedMesh = mesh;
130         t.GetComponent<MeshCollider>().sharedMesh = mesh;
131         t.GetComponent<MeshRenderer>().sharedMaterial = mat;
132
133         t.gameObject.SetActive(true);
134         terrainObj.SetActive(false);
135     }
136 }

TerrainToMeshConverter

渲染地形的shader如下:

 1 Shader "Custom/TerrainDiffuse"
 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 VertexData
28             {
29                 float4 Pos : POSITION;
30                 float4 Tangent : TANGENT;
31                 float2 uv : TEXCOORD0;
32             };
33
34             struct V2F
35             {
36                 float4 Pos : SV_POSITION;
37                 float4 Color : COLOR;
38                 float2 uv : TEXCOORD0;
39             };
40
41             V2F Vert(VertexData v)
42             {
43                 V2F o;
44                 o.Pos = mul(UNITY_MATRIX_MVP, v.Pos);
45                 o.Color = v.Tangent;
46                 o.uv = v.uv;
47                 return o;
48             }
49
50             float4 Frag(V2F i) : COLOR
51             {
52                 float4 t0 = tex2D(_Texture0, i.uv);
53                 float4 t1 = tex2D(_Texture1, i.uv);
54                 float4 t2 = tex2D(_Texture2, i.uv);
55                 float4 t3 = tex2D(_Texture3, i.uv);
56
57                 return t0 * i.Color.x + t1 * i.Color.y + t2 * i.Color.z + t3 * i.Color.w;
58             }
59
60             ENDCG
61         }
62     }
63 }

Shader

生成的mesh与原terrain对比如下,左边为mesh,右边为terrain:

性能对比如下:

mesh:

terrain:

转载请注明出处:

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

时间: 2024-10-13 15:24:03

Unity3d之将terrain转化成mesh的相关文章

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

#pragma strict function Awake(){ var pMeshFilter : MeshFilter = gameObject.AddComponent(typeof(MeshFilter)) as MeshFilter;//网格过滤器 var pMeshRender : MeshRenderer = gameObject.AddComponent(typeof(MeshRenderer)) as MeshRenderer;//网格渲染 var pMesh : Mesh =

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

NavMesh(导航网格)是3D游戏世界中用于实现动态物体自动寻路的一种技术,将游戏中复杂的结构组织关系简化为带有一定信息的网格,在这些网格的基础上通过一系列的计算来实现自动寻路..导航时,只需要给导航物体挂载导航组建,导航物体便会自行根据目标点来寻找最直接的路线,并沿着该线路到达目标点. 下面通过一个简单的Sample来介绍NavMesh的应用: 1.在Scene中新建三个Cube,如下图摆放. 2.选中上图三个Cube,并在Inspector面板中选中为静态(static)下拉选项的Navi

Unity3D动态创建地形网格(一)

最近一直都在搞flash3D,好像有点对不起Unity3D的朋友们了.这次简单的写一个动态创建地形网格的脚本给大家分享一下. 这次是第一部分,仅仅实现了通过高度图动态生成地形的部分.假如以后有心情和时间,再来慢慢的补充多通道刷地形材质.动态刷地形和保存高度图等的功能吧.以前我都不喜欢公开脚本源码,都是一个个部分的单独讲解然后让朋友们自己去组合起来的,但最近时间实在是不多,所以还是直接提供源码,然后在源码上面写注释,大家自行的观看吧.源码在最下面. 首先直接把脚本拖到某物体上面,运行,就会出现了上

基于Unity3D三维模型的动作插值(空间关键帧动画实现)

1.引言 最近在Unity3D中实现一个基于自定义Mesh网格的骨骼动画.存储关键帧信息,然后通过插值形成中间动画.网格GameObject之间存在父子关系.插值动画对模型骨骼的Position.Sclae.Rotation三个部分分别混合插值. 并且注意,一般选取的是子骨骼相对父骨骼的Transform信息,即上述关键帧信息具体应该为Transform.localPosition.localScale.localRotation. 并且这个系统的关键帧是定义在三维空间中的,用户在一系列关键帧点

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

在开始正文前,先说下Axiom3D里遇到的二个BUG. 1.在启动axiom生成的程序中,我发现输出里总是有一些如"billboard_type","billboard_origin"这些不能解析,我开始还在想是不是文件格式版本过期或是啥的,反正后面我查了下,发现这些是有对应解析类的,在对比对应的Ogre相应位置代码,发现ParticleSystemRenderer在Ogre中是多重继承,C#天生不支持,但是我发现ScriptableObject本身是从Dispos

(转载)Unity3d中3D Text对模型的穿透显示

Unity3D中使用3D Text(Text Mesh)时,如何让场景中的物体和3D Text有正确的遮挡关系.由于3D Text默认材质是(Font Material),他的shader是GUI/Text Shader,自然也就有了GUI的穿透特性,所以我们使用自定义材质就可以解决这个问题了. 1.新建材质,并将如下shader设置给它 Shader "Custom/3D Text Shader" { Properties { _MainTex ("Font Texture

Direct-X学习笔记--天空盒

学习了三维的地形系统之后,该抬头看看天空啦.下面学习一下传说中的三维天空系统.其实三维天空的实现比地形系统简单得多,我们只需要用一点点小伎俩,就可以蒙混大多数人. 一.简介 我们在玩游戏的时候,尤其是野外的大场景中,要想更逼真离不开三维天空系统.要用程序来模拟无边无际的天空是不可能的,而聪明的前辈们自然也想到了用"天圆地方"这种古代人们对于天空的认识来作为三维天空设计思想.即用一个足够大的面罩住我们,只要这个罩足够大,在里面看天空就和真实的天空没什么区别啦.而基于这种思想的天空设计方案

Direct-X学习笔记--封装一个网格模型类

之前学习了网格模型的导入,绘制,了解了X文件等相关知识,但是,那样绘制比较麻烦,而且绘制一个模型需要好多代码,完全是面向过程的思维,这次,学习一下怎么把网格模型的导入以及绘制等功能封装在一个类中.顺便加深一下对World Transform的理解.感觉自己的3D思维还是没有培养起来,想绘制一个对象,绘制出来和想象中的位置相差甚远. 一.复习一下网格模型相关知识 网格模型就是一个我们在美术工具中制作好的资源,通过一些API接口我们可以将美术童鞋做好的模型很方便的导入程序中.我们只需要了解怎样从文件

VR沉浸体验的要求

以下为演讲实录:大家好!今天我来这里主要介绍的是使用UE4做VR内容的一些优化技巧.VR需要给大家一个沉浸式的体验,这要求两点:一点是你的画面要尽可能的精美,另外一点是你的呈现要尽可能的流畅. 这两点其实是相互矛盾的,因为你画面做的越细致.越精美,其实你的内容就越重,你的渲染压力也就越大.你要做到75帧双眼同时渲染难度就非常高. 我们看用UE4引擎帮你做了多少事情,第一个已经早就完成了.引擎的输入更新并不是只有一次,传统引擎输入可能是游戏线程一开始有个输入,把所有这帧的输入都获取.获取完之后游戏