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

http://blog.csdn.net/zr339361504/article/details/53352800

 

前言

unity加载烘培贴图是需要加载场景才可以使用,但如果项目只使用一个场景或者有许多关卡地形时,明显通过加载场景来达到更换烘培贴图的这种做法是不妥当的。而terrain地形在有些安卓机上的支持并不是很好,所以有必要把地形转为网格。庆幸的是,网上也有这方面的代码,所以借鉴了网上大神的代码,整合出一套动态加载烘培贴图与地形转网格的方案。
借鉴的网站:
http://www.xuanyusong.com/archives/3807
http://www.cnblogs.com/jietian331/p/5831062.html

一、动态加载烘培贴图。

1、烘培贴图的原理

烘培贴图实际上就是把静态物体上的阴影与光照保存成多张png贴图,并保存每个静态物体对应烘培贴图的编号、裁剪大小与裁剪偏移量。最后,静态物体与关联的裁剪纹理在shader里进行处理。

2、有用的数据

我们知道烘培以后会生成Lightmap Data Asset(5.3之前叫LightmapSnapshot)、贴图、与SkyboxProbe。实际上真正运行的时候只需要贴图以及上面说的每个静态物体对应烘培贴图的编号、裁剪大小与裁剪偏移量。所以,我们只需要把裁剪信息保存起来就可以了。

3、数据保存

我们可以使用文件来保存这些数据,但是有一种更方便的做法,也是本文用到的方法。就是通过挂载脚本,把数据存放在脚本中,在做成预置。这样的做法,就可以把数据完完整整的保存在预置里。

二、Terrain转Mesh

1、实现原理

首先我们要明白,要生成网格需要顶点、三角面,如果有贴图光照还需要uv和发现。明白了这点,我们就可以从这几个方向下手。只要获取到地图的宽高作为行与列,用行与列对应的点作为x与z坐标,再根据此点获取地形高度作为z坐标,就可以生成顶点,再根据顶点来连接三角面。uv坐标也类似,只是把范围缩放到0与1。

2、有用的数据

生成地形网格,我们需要保存顶点数据、瓦片贴图权重、瓦片uv坐标、光照贴图uv坐标、三角面、以及。由于与地形的光照部分直接使用烘培贴图,所以法线可以不用记录。

3、数据保存

之前曾视图使用.obj格式来保存网格数据,但是查看了一下.obj的数据格式,发现其只支持一套uv坐标,不支持多套。所以只能用上面提到的使用脚本预置来保存数据。

三、使用方法

创建一个空物体,添加PrefabLightmapData脚本,并把所有地形相关物体都放在空物体上,成为其子节点。点击Bake/Bake Prefab Lightmaps便可以。生成以后,需要运行一次才会设置材质。有个地方需要注意,由于项目出于效率的考虑,Directional Mode需要设置为Non-Directional。

四、代码

1、PrefabLightmapData.cs

#if UNITY_EDITOR
using UnityEditor;
using System.IO;
#endif
using UnityEngine;
using System.Collections.Generic;
[DisallowMultipleComponent, ExecuteInEditMode]
public class PrefabLightmapData : MonoBehaviour
{
    [System.Serializable]
    struct RendererInfo
    {
        public Renderer renderer;
        public int lightmapIndex;
        public Vector4 lightmapOffsetScale;
    }
    [System.Serializable]
    struct TerrainInfo
    {
        public int lightmapIndex;
        public Vector4 lightmapOffsetScale;
    }

    [System.Serializable]
    public struct FogInfo
    {
        public bool fog;
        public FogMode fogMode;
        public Color fogColor;
        public float fogStartDistance;
        public float fogEndDistance;
        public float fogDensity;
    } 

    [SerializeField]
    TerrainInfo[] m_TerrainInfo;
    [SerializeField]
    RendererInfo[] m_RendererInfo;
    [SerializeField]
    Texture2D[] m_Lightmaps;
    [SerializeField]
    Texture2D[] m_Lightmaps2;
    [SerializeField]
    FogInfo m_FogInfo; 

    const string LIGHTMAP_RESOURCE_PATH = "Assets/Resources/Lightmaps/";

    [System.Serializable]
    struct Texture2D_Remap
    {
        public int originalLightmapIndex;
        public Texture2D originalLightmap;
        public Texture2D lightmap0;
        public Texture2D lightmap1;
    }

    static List<Texture2D_Remap> sceneLightmaps = new List<Texture2D_Remap>();

    void Awake()
    {
        ApplyLightmaps(m_RendererInfo, m_TerrainInfo, m_Lightmaps, m_Lightmaps2,m_FogInfo);

        for (int i = 0; i < m_TerrainInfo.Length; i++)
        {
            var info = m_TerrainInfo[i];
            TerrainToMeshData terrianMeshData = GetComponentInChildren<TerrainToMeshData>();
            if (terrianMeshData)
                terrianMeshData.setMaterial(info.lightmapIndex);
        }
    }

    static void ApplyLightmaps(RendererInfo[] rendererInfo, TerrainInfo[] terrainInfo, Texture2D[] lightmaps, Texture2D[] lightmaps2, FogInfo fogInfo)
    {
        for (int i = 0; i < rendererInfo.Length; i++)
        {
            var info = rendererInfo[i];
            info.renderer.lightmapScaleOffset = info.lightmapOffsetScale;
            info.renderer.lightmapIndex = info.lightmapIndex;
        }

        LightmapData[] combinedLightmaps2 = new LightmapData[lightmaps.Length];
        for (int i = 0; i < lightmaps.Length; i++)
        {
            combinedLightmaps2[i] = new LightmapData();
            combinedLightmaps2[i].lightmapFar = lightmaps[i];
            combinedLightmaps2[i].lightmapNear = lightmaps2[i];
        }
        LightmapSettings.lightmaps = combinedLightmaps2;

        RenderSettings.fog = fogInfo.fog;
        RenderSettings.fogMode = fogInfo.fogMode;
        RenderSettings.fogColor = fogInfo.fogColor;
        RenderSettings.fogStartDistance = fogInfo.fogStartDistance;
        RenderSettings.fogEndDistance = fogInfo.fogEndDistance;
        RenderSettings.fogDensity = fogInfo.fogDensity;

        LightmapSettings.lightmapsMode = LightmapsMode.NonDirectional;

        //bool existsAlready = false;
        //int counter = 0;
        //int[] lightmapArrayOffsetIndex;

        //if (rendererInfo == null || rendererInfo.Length == 0)
        //    return;

        //LightmapSettings.lightmapsMode = LightmapsMode.NonDirectional;
        //var settingslightmaps = LightmapSettings.lightmaps;
        //var combinedLightmaps = new List<LightmapData>();
        //lightmapArrayOffsetIndex = new int[lightmaps.Length];

        //for (int i = 0; i < lightmaps.Length; i++)
        //{
        //    existsAlready = false;
        //    for (int j = 0; j < settingslightmaps.Length; j++)
        //    {
        //        if (lightmaps[i] == settingslightmaps[j].lightmapFar)
        //        {
        //            lightmapArrayOffsetIndex[i] = j;
        //            existsAlready = true;
        //        }
        //    }

        //    if (!existsAlready)
        //    {
        //        lightmapArrayOffsetIndex[i] = counter + settingslightmaps.Length;
        //        var newLightmapData = new LightmapData();
        //        newLightmapData.lightmapFar = lightmaps[i];
        //        newLightmapData.lightmapNear = lightmaps2[i];
        //        combinedLightmaps.Add(newLightmapData);
        //        ++counter;
        //    }
        //}

        //var combinedLightmaps2 = new LightmapData[settingslightmaps.Length + counter];
        //settingslightmaps.CopyTo(combinedLightmaps2, 0);

        //if (counter > 0)
        //{
        //    for (int i = 0; i < combinedLightmaps.Count; i++)
        //    {
        //        combinedLightmaps2[i + settingslightmaps.Length] = new LightmapData();
        //        combinedLightmaps2[i + settingslightmaps.Length].lightmapFar = combinedLightmaps[i].lightmapFar;
        //        combinedLightmaps2[i + settingslightmaps.Length].lightmapNear = combinedLightmaps[i].lightmapNear;
        //    }
        //}

        //ApplyRendererInfo(rendererInfo, lightmapArrayOffsetIndex);

        //LightmapSettings.lightmaps = combinedLightmaps2;
    }

    static void ApplyRendererInfo(RendererInfo[] infos, int[] arrayOffsetIndex)
    {
        for (int i = 0; i < infos.Length; i++)
        {
            var info = infos[i];
            info.renderer.lightmapIndex = arrayOffsetIndex[info.lightmapIndex];
            info.renderer.lightmapScaleOffset = info.lightmapOffsetScale;
        }
    }

#if UNITY_EDITOR
    [MenuItem("Bake/Update Scene with Prefab Lightmaps")]
    static void UpdateLightmaps()
    {
        PrefabLightmapData[] prefabs = FindObjectsOfType<PrefabLightmapData>();

        foreach (var instance in prefabs)
        {
            ApplyLightmaps(instance.m_RendererInfo, instance.m_TerrainInfo, instance.m_Lightmaps, instance.m_Lightmaps2, instance.m_FogInfo);
        }

        Debug.Log("Prefab lightmaps updated");
    }

    [MenuItem("Bake/Bake Prefab Lightmaps")]
    static void GenerateLightmapInfo()
    {
        Debug.ClearDeveloperConsole();

        if (Lightmapping.giWorkflowMode != Lightmapping.GIWorkflowMode.OnDemand)
        {
            Debug.LogError("ExtractLightmapData requires that you have baked you lightmaps and Auto mode is disabled.");
            return;
        }

        Lightmapping.Bake();

        string lightMapPath = System.IO.Path.Combine(Directory.GetCurrentDirectory(), LIGHTMAP_RESOURCE_PATH);

        if (!Directory.Exists(lightMapPath))
            Directory.CreateDirectory(lightMapPath);

        sceneLightmaps = new List<Texture2D_Remap>();

        //var scene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();
        var sceneName = Path.GetFileNameWithoutExtension(EditorApplication.currentScene);
        var resourcePath = LIGHTMAP_RESOURCE_PATH + sceneName;
        var scenePath = System.IO.Path.GetDirectoryName(EditorApplication.currentScene) + "/" + sceneName + "/";

        PrefabLightmapData[] prefabs = FindObjectsOfType<PrefabLightmapData>();
        foreach (var instance in prefabs)
        {
            var gameObject = instance.gameObject;
            var rendererInfos = new List<RendererInfo>();
            var terrainInfo = new List<TerrainInfo>();

            var lightmaps = new List<Texture2D>();
            var lightmaps2 = new List<Texture2D>();
            GenerateLightmapInfo(scenePath, resourcePath, gameObject, rendererInfos, terrainInfo, lightmaps, lightmaps2);

            instance.m_RendererInfo = rendererInfos.ToArray();
            instance.m_Lightmaps = lightmaps.ToArray();
            instance.m_Lightmaps2 = lightmaps2.ToArray();
            instance.m_TerrainInfo = terrainInfo.ToArray();

            instance.m_FogInfo = new FogInfo();
            instance.m_FogInfo.fog = RenderSettings.fog;
            instance.m_FogInfo.fogMode = RenderSettings.fogMode;
            instance.m_FogInfo.fogColor = RenderSettings.fogColor;
            instance.m_FogInfo.fogStartDistance = RenderSettings.fogStartDistance;
            instance.m_FogInfo.fogEndDistance = RenderSettings.fogEndDistance;

            var targetPrefab = PrefabUtility.GetPrefabParent(gameObject) as GameObject;
            if (targetPrefab != null)
            {
                //Prefab
                PrefabUtility.ReplacePrefab(gameObject, targetPrefab);
            }

            ApplyLightmaps(instance.m_RendererInfo, instance.m_TerrainInfo, instance.m_Lightmaps, instance.m_Lightmaps2, instance.m_FogInfo);
        }

        Debug.Log("Update to prefab lightmaps finished");
    }

    static void GenerateLightmapInfo(string scenePath, string resourcePath, GameObject root, List<RendererInfo> rendererInfos, List<TerrainInfo> terrainInfo, List<Texture2D> lightmaps, List<Texture2D> lightmaps2)
    {
        var renderers = root.GetComponentsInChildren<Renderer>();
        foreach (Renderer renderer in renderers)
        {
            if (renderer.lightmapIndex != -1)
            {
                RendererInfo info = new RendererInfo();
                info.renderer = renderer;
                info.lightmapOffsetScale = renderer.lightmapScaleOffset;

                Texture2D lightmap = LightmapSettings.lightmaps[renderer.lightmapIndex].lightmapFar;
                Texture2D lightmap2 = LightmapSettings.lightmaps[renderer.lightmapIndex].lightmapNear;
                int sceneLightmapIndex = AddLightmap(scenePath, resourcePath, renderer.lightmapIndex, lightmap, lightmap2);

                info.lightmapIndex = lightmaps.IndexOf(sceneLightmaps[sceneLightmapIndex].lightmap0);
                if (info.lightmapIndex == -1)
                {
                    info.lightmapIndex = lightmaps.Count;
                    lightmaps.Add(sceneLightmaps[sceneLightmapIndex].lightmap0);
                    lightmaps2.Add(sceneLightmaps[sceneLightmapIndex].lightmap1);
                }

                rendererInfos.Add(info);
            }
        }

        Terrain terrain = root.GetComponentInChildren<Terrain>();
        if (terrain != null)
        {
            TerrainInfo info = new TerrainInfo();
            info.lightmapOffsetScale = terrain.lightmapScaleOffset;

            Texture2D lightmap = LightmapSettings.lightmaps[terrain.lightmapIndex].lightmapFar;
            Texture2D lightmap2 = LightmapSettings.lightmaps[terrain.lightmapIndex].lightmapNear;
            int sceneLightmapIndex = AddLightmap(scenePath, resourcePath, terrain.lightmapIndex, lightmap, lightmap2);

            info.lightmapIndex = lightmaps.IndexOf(sceneLightmaps[sceneLightmapIndex].lightmap0);
            if (info.lightmapIndex == -1)
            {
                info.lightmapIndex = lightmaps.Count;
                lightmaps.Add(sceneLightmaps[sceneLightmapIndex].lightmap0);
                lightmaps2.Add(sceneLightmaps[sceneLightmapIndex].lightmap1);
            }

            terrainInfo.Add(info);

            //添加一个game object,挂载一个转换mesh的脚本。
            GameObject terrainScriptObj = GameObject.CreatePrimitive(PrimitiveType.Cube);
            GameObject.DestroyImmediate(terrainScriptObj.GetComponent<MeshFilter>());
            GameObject.DestroyImmediate(terrainScriptObj.GetComponent<MeshRenderer>());
            GameObject.DestroyImmediate(terrainScriptObj.GetComponent<BoxCollider>());
            terrainScriptObj.transform.parent = terrain.transform.parent;
            terrainScriptObj.transform.position = terrain.transform.position;
            terrainScriptObj.name = "TerrainMesh";
            TerrainToMeshData terrainToMesh = terrainScriptObj.AddComponent<TerrainToMeshData>();
            TerrainToMeshData.ConvertTerrianToMesh(terrain.gameObject);

            GameObject.DestroyImmediate(terrain.gameObject);
        } 
    }

    static int AddLightmap(string scenePath, string resourcePath, int originalLightmapIndex, Texture2D lightmap, Texture2D lightmap2)
    {
        int newIndex = -1;

        for (int i = 0; i < sceneLightmaps.Count; i++)
        {
            if (sceneLightmaps[i].originalLightmapIndex == originalLightmapIndex)
            {
                return i;
            }
        }

        if (newIndex == -1)
        {
            var lightmap_Remap = new Texture2D_Remap();
            lightmap_Remap.originalLightmapIndex = originalLightmapIndex;
            lightmap_Remap.originalLightmap = lightmap;

            var filename = scenePath + "Lightmap-" + originalLightmapIndex;

            lightmap_Remap.lightmap0 = GetLightmapAsset(filename + "_comp_light.exr", resourcePath + "_light", originalLightmapIndex, lightmap);
            if (lightmap2 != null)
            {
                lightmap_Remap.lightmap1 = GetLightmapAsset(filename + "_comp_dir.exr", resourcePath + "_dir", originalLightmapIndex, lightmap2);
            }
            sceneLightmaps.Add(lightmap_Remap);
            newIndex = sceneLightmaps.Count - 1;
        }

        return newIndex;
    }

    static Texture2D GetLightmapAsset(string filename, string resourcePath, int originalLightmapIndex, Texture2D lightmap)
    {
        //AssetDatabase.ImportAsset(filename, ImportAssetOptions.ForceUpdate);
        //var importer = AssetImporter.GetAtPath(filename) as TextureImporter;
        //importer.isReadable = true;
        //AssetDatabase.ImportAsset(filename, ImportAssetOptions.ForceUpdate);

        //var assetLightmap = AssetDatabase.LoadAssetAtPath<Texture2D>(filename);

        //var assetPath = resourcePath + "-" + originalLightmapIndex + ".asset";
        //var newLightmap = Instantiate<Texture2D>(assetLightmap);

        //AssetDatabase.CreateAsset(newLightmap, assetPath);

        //newLightmap = AssetDatabase.LoadAssetAtPath<Texture2D>(assetPath);

        //importer.isReadable = false;
        //AssetDatabase.ImportAsset(filename, ImportAssetOptions.ForceUpdate);

        var assetPath = resourcePath + "-" + originalLightmapIndex + ".exr";
        AssetDatabase.CopyAsset(filename, assetPath);

        AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate);
        var importer = AssetImporter.GetAtPath(assetPath) as TextureImporter;
        importer.isReadable = true;
        AssetDatabase.ImportAsset(filename, ImportAssetOptions.ForceUpdate);
        var assetLightmap = AssetDatabase.LoadAssetAtPath<Texture2D>(assetPath);
        importer.isReadable = false;
        AssetDatabase.ImportAsset(filename, ImportAssetOptions.ForceUpdate);
        return assetLightmap;
    }
#endif

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364

2、TerrainToMeshData.cs

using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
[DisallowMultipleComponent, ExecuteInEditMode]
public class TerrainToMeshData : MonoBehaviour
{
    [SerializeField]
    Vector3[] m_Vertices;
    [SerializeField]
    Vector3[] m_Normals;    //法线可以不用,因为直接用烘培贴图。
    [SerializeField]
    Vector2[] m_Uvs;
    [SerializeField]
    Vector2[] m_Uv2s;
    [SerializeField]
    Vector4[] m_AlphasWeight;
    [SerializeField]
    int[] m_Triangles;
    [SerializeField]
    Texture2D[] m_Texture;

    void Start()
    {
        MeshFilter meshFilter = gameObject.GetComponent<MeshFilter>();
        MeshRenderer meshRender = gameObject.GetComponent<MeshRenderer>();
        if (meshFilter == null)
            meshFilter = gameObject.AddComponent<MeshFilter>();

        if (meshRender == null)
            meshRender = gameObject.AddComponent<MeshRenderer>();


        Mesh mesh = new Mesh();
        mesh.vertices = m_Vertices;
        mesh.uv = m_Uvs;
        mesh.uv2 = m_Uv2s;
        mesh.triangles = m_Triangles;
        mesh.tangents = m_AlphasWeight;
        //mesh.normals = m_Normals;
        mesh.Optimize();

        meshFilter.sharedMesh = mesh;
    }

    public void setMaterial(int lightMapIndex)
    {
        MeshRenderer meshRender = gameObject.GetComponent<MeshRenderer>();
        if (meshRender == null)
            meshRender = gameObject.AddComponent<MeshRenderer>();

        var mat = new Material(Shader.Find("shader/Transparent/TerrainDiffuseLightMap"));
        for (int i = 0; i < m_Texture.Length; i++)
        {
            //目前只支持4张贴图最多
            if (i > 4)
                break;
            mat.SetTexture("_Texture" + i, m_Texture[i]);
        }
        mat.SetTexture("_LightMap", LightmapSettings.lightmaps[lightMapIndex].lightmapFar);
        meshRender.material = mat;
    }

    public static void ConvertTerrianToMesh(GameObject _terrainObj = null)
    {
        TerrainToMesh(_terrainObj);
    }

    private static void TerrainToMesh(GameObject _terrainObj)
    {
        var terrainObj = _terrainObj;
        if (terrainObj == null)
        {
            Debug.Log("terrainObj == null");
        }

        var terrain = terrainObj.GetComponent<Terrain>();
        if (terrain == null)
        {
            Debug.Log("terrain == null");
            return;
        }

        var terrainData = terrain.terrainData;
        if (terrainData == null)
        {
            Debug.Log("terrainData == null");
            return;
        }
        //将顶点数稀释 vertexCountScale*vertexCountScale 倍
        int vertexCountScale = 1;
        int w = terrainData.heightmapWidth;
        int h = terrainData.heightmapHeight;
        Vector3 size = terrainData.size;

        float[, ,] alphaMapData = terrainData.GetAlphamaps(0, 0, terrainData.alphamapWidth, terrainData.alphamapHeight);
        Vector3 meshScale = new Vector3(size.x / (w - 1f) * vertexCountScale, 1, size.z / (h - 1f) * vertexCountScale);
        //此处有问题,若每个图片大小不一,则出问题。日后改善
        Vector2 uvScale = new Vector2(1f / (w - 1f), 1f / (h - 1f)) * vertexCountScale * (size.x / terrainData.splatPrototypes[0].tileSize.x);
        Vector2 uv2Scale = new Vector2(1f / (w - 1f), 1f / (h - 1f));

        w = (w - 1) / vertexCountScale + 1;
        h = (h - 1) / vertexCountScale + 1;
        Vector3[] vertices = new Vector3[w * h];
        Vector2[] uvs = new Vector2[w * h];
        Vector2[] uv2s = new Vector2[w * h];

        // 只支持4张图片,每个顶点每个图片所占比重
        Vector4[] alphasWeight = new Vector4[w * h];
        Vector3[] normals = new Vector3[w * h];


        for (int i = 0; i < w; i++)
        {
            for (int j = 0; j < h; j++)
            {
                int index = j * w + i;
                float z = terrainData.GetHeight(i * vertexCountScale, j * vertexCountScale);
                vertices[index] = Vector3.Scale(new Vector3(i, z, j), meshScale);
                uvs[index] = Vector2.Scale(new Vector2(i, j), uvScale);
                uv2s[index] = Vector2.Scale(new Vector2(i, j), uv2Scale);

                // alpha map
                int i2 = (int)(i * terrainData.alphamapWidth / (w - 1f));
                int j2 = (int)(j * terrainData.alphamapHeight / (h - 1f));
                i2 = Mathf.Min(terrainData.alphamapWidth - 1, i2);
                j2 = Mathf.Min(terrainData.alphamapHeight - 1, j2);
                var alpha0 = alphaMapData[j2, i2, 0];
                var alpha1 = alphaMapData[j2, i2, 1];
                var alpha2 = alphaMapData[j2, i2, 2];
                var alpha3 = 0f;
                if (terrainData.splatPrototypes.Length > 3)
                    alpha3 = alphaMapData[j2, i2, 3];
                alphasWeight[index] = new Vector4(alpha0, alpha1, alpha2, alpha3);
            }
        }

        /*
         * 三角形
         *     b       c
         *      *******
         *      *   * *
         *      * *   *
         *      *******
         *     a       d
         */
        int[] triangles = new int[(w - 1) * (h - 1) * 6];
        int triangleIndex = 0;
        for (int i = 0; i < w - 1; i++)
        {
            for (int j = 0; j < h - 1; j++)
            {
                int a = j * w + i;
                int b = (j + 1) * w + i;
                int c = (j + 1) * w + i + 1;
                int d = j * w + i + 1;

                triangles[triangleIndex++] = a;
                triangles[triangleIndex++] = b;
                triangles[triangleIndex++] = c;

                triangles[triangleIndex++] = a;
                triangles[triangleIndex++] = c;
                triangles[triangleIndex++] = d;

                //计算法线
                //var side1 = vertices[b] - vertices[a];
                //var side2 = vertices[c] - vertices[a];
                //var perp = Vector3.Cross(side1, side2);
                //perp /= perp.magnitude;
                //normals[a] = perp;
            }
        }

        Mesh mesh = new Mesh();
        mesh.vertices = vertices;
        mesh.uv = uvs;
        mesh.triangles = triangles;
        //这里用切线来记录,但是跟切线毛关系都没,只是为了传给shader
        mesh.tangents = alphasWeight;
        mesh.normals = normals;
        mesh.RecalculateNormals();
        mesh.Optimize();

        TerrainToMeshData[] prefabs = FindObjectsOfType<TerrainToMeshData>();
        prefabs[0].m_AlphasWeight = alphasWeight;
        prefabs[0].m_Texture = new Texture2D[terrainData.splatPrototypes.Length];
        //prefabs[0].m_Normals = mesh.normals;
        prefabs[0].m_Uvs = uvs;
        prefabs[0].m_Uv2s = uv2s;
        prefabs[0].m_Vertices = vertices;
        prefabs[0].m_Triangles = triangles;
        prefabs[0].transform.parent = terrainObj.transform.parent;
        prefabs[0].transform.position = terrainObj.transform.position;
        prefabs[0].gameObject.layer = terrainObj.layer;
        for (int i = 0; i < terrainData.splatPrototypes.Length; i++)
        {
            prefabs[0].m_Texture[i] = terrainData.splatPrototypes[i].texture;
        }
    }
}

3、TerrainDiffuseLightMap.shader

// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'

Shader "shader/Transparent/TerrainDiffuseLightMap" {
    Properties
    {
        _Texture0 ("Texture 1", 2D) = "white" {}
        _Texture1 ("Texture 2", 2D) = "white" {}
        _Texture2 ("Texture 3", 2D) = "white" {}
        _Texture3 ("Texture 4", 2D) = "white" {}
        _LightMap ("Lightmap (RGB)", 2D) = "white" {}
    }

    SubShader
    {
        Tags {"RenderType"="Opaque"}
        LOD 200

        Pass
        {
            CGPROGRAM
            #pragma vertex Vert
            #pragma fragment Frag

            #include "UnityCG.cginc"

            sampler2D _Texture0;
            sampler2D _Texture1;
            sampler2D _Texture2;
            sampler2D _Texture3;
            sampler2D _LightMap;
            float4 _LightMap_ST;
            float4 _Texture0_ST;
            float4 _Texture1_ST;
            float4 _Texture2_ST;
            float4 _Texture3_ST;

            struct VertexData
            {
                float4 Pos : POSITION;
                float4 Tangent : TANGENT;
                float2 uv : TEXCOORD0;
                float2 uv2 : TEXCOORD1;
            };

            struct V2F
            {
                float4 Pos : SV_POSITION;
                float4 color : COLOR;
                float2 uv : TEXCOORD0; 
                float2 uv2 : TEXCOORD1;
            };

            V2F Vert(VertexData v)
            {
                V2F o;
                o.Pos = mul(UNITY_MATRIX_MVP, v.Pos);
                o.color = v.Tangent;
                o.uv = v.uv;
                o.uv2 = v.uv2;
                return o;
            }

            float4 Frag(V2F i) : COLOR
            {
                float4 t0 = tex2D(_Texture0, TRANSFORM_TEX(i.uv, _Texture0));
                float4 t1 = tex2D(_Texture1, TRANSFORM_TEX(i.uv, _Texture1));
                float4 t2 = tex2D(_Texture2, TRANSFORM_TEX(i.uv, _Texture2));
                float4 t3 = tex2D(_Texture3, TRANSFORM_TEX(i.uv, _Texture3));
                fixed4 texcolor = t0 * i.color.x + t1 * i.color.y + t2 * i.color.z + t3 * i.color.w;
                UNITY_OPAQUE_ALPHA(texcolor.a);

                texcolor.rgb *= DecodeLightmap(tex2D(_LightMap, TRANSFORM_TEX(i.uv2, _LightMap)));  
                return texcolor;
            }

            ENDCG
        }
    } 
    FallBack "Diffuse"
}

 

版权声明:本文为博主原创文章,未经博主允许不得转载。
posted @ 2017-11-24 14:33  三页菌  阅读(409)  评论(0编辑  收藏  举报