zoukankan      html  css  js  c++  java
  • 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

    光照效果如下:

  • 相关阅读:
    Linux中的阻塞机制
    Shellz中awk的简单用法
    实际项目开发过程中常用C语言函数的9大用法
    堆栈溢出一般是什么原因?
    哈夫曼算法原理
    7款易上手C语言编程软件推荐
    嵌入式系统分类介绍
    什么是字符串数组
    C语言中数组定义方式
    第三章课后习题P56解析
  • 原文地址:https://www.cnblogs.com/jietian331/p/5831062.html
Copyright © 2011-2022 走看看