Unity3D中的地形轉成模型

using UnityEngine;
using UnityEditor; 
using System; 
using System.Collections; 
using System.IO;
using System.Text; 
enum SaveFormat { Triangles, Quads }
enum SaveResolution { Full=0, Half, Quarter, Eighth, Sixteenth }
class ExportTerrain : EditorWindow 
{ 
    SaveFormat saveFormat = SaveFormat.Triangles;
    SaveResolution saveResolution = SaveResolution.Half; 
    static TerrainData terrain; 
    static Vector3 terrainPos; 
    int tCount; int counter; int totalCount; int progressUpdateInterval = 10000;

    [MenuItem("Terrain/Export To Obj...")] 
    static void Init() { 
        terrain = null; 
        Terrain terrainObject = Selection.activeObject as Terrain; 
        if (!terrainObject) 
        { 
            terrainObject = Terrain.activeTerrain; 
        } 
        if (terrainObject) 
        {
            terrain = terrainObject.terrainData; terrainPos = terrainObject.transform.position;
        }

        EditorWindow.GetWindow<ExportTerrain>().Show();
    } 

    void OnGUI() 
    { 
        if (!terrain) { 
            GUILayout.Label("No terrain found"); 
            if (GUILayout.Button("Cancel"))
            { 
                EditorWindow.GetWindow<ExportTerrain>().Close();
            } 
            return;
        }
        saveFormat = (SaveFormat) EditorGUILayout.EnumPopup("Export Format", saveFormat); 
        saveResolution = (SaveResolution) EditorGUILayout.EnumPopup("Resolution", saveResolution); 
        if (GUILayout.Button("Export"))
        {
            Export(); 
        } 
    } 
    void Export()
    { 
        string fileName = EditorUtility.SaveFilePanel("Export .obj file", "", "Terrain", "obj");
        int w = terrain.heightmapWidth; 
        int h = terrain.heightmapHeight;
        Vector3 meshScale = terrain.size; 
        int tRes = (int)Mathf.Pow(2, (int)saveResolution );
        meshScale = new Vector3(meshScale.x / (w - 1) * tRes, meshScale.y, meshScale.z / (h - 1) * tRes); Vector2 uvScale = new Vector2(1.0f / (w - 1), 1.0f / (h - 1));
        float[,] tData = terrain.GetHeights(0, 0, w, h); 
        w = (w - 1) / tRes + 1; h = (h - 1) / tRes + 1; 
        Vector3[] tVertices = new Vector3[w * h]; 
        Vector2[] tUV = new Vector2[w * h];
        int[] tPolys; 
        if (saveFormat == SaveFormat.Triangles)
        { 
        tPolys = new int[(w - 1) * (h - 1) * 6];
        } else { 
            tPolys = new int[(w - 1) * (h - 1) * 4];
        } 
        // Build vertices and UVs 
        for (int y = 0; y < h; y++) 
        {
            for (int x = 0; x < w; x++) 
            { 
                tVertices[y * w + x] = Vector3.Scale(meshScale, new Vector3(-y, tData[x * tRes, y * tRes], x)) + terrainPos; tUV[y * w + x] = Vector2.Scale( new Vector2(x * tRes, y * tRes), uvScale);
            } 
        } 
        int index = 0;
        if (saveFormat == SaveFormat.Triangles) 
        { 
            // Build triangle indices: 3 indices into vertex array for each triangle 
            for (int y = 0; y < h - 1; y++)
            { for (int x = 0; x < w - 1; x++)
                {
                    // For each grid cell output two triangles
                tPolys[index++] = (y * w) + x; 
                tPolys[index++] = ((y + 1) * w) + x; 
                tPolys[index++] = (y * w) + x + 1;
                tPolys[index++] = ((y + 1) * w) + x; 
                tPolys[index++] = ((y + 1) * w) + x + 1; 
                tPolys[index++] = (y * w) + x + 1; } 
            }
        } else {
            // Build quad indices: 4 indices into vertex array for each quad
            for (int y = 0; y < h - 1; y++)
            { for (int x = 0; x < w - 1; x++)
                { // For each grid cell output one quad 
                    tPolys[index++] = (y * w) + x; tPolys[index++] = ((y + 1) * w) + x;
                    tPolys[index++] = ((y + 1) * w) + x + 1; tPolys[index++] = (y * w) + x + 1; 
                } 
            }
        } 
        // Export to .obj
        StreamWriter sw = new StreamWriter(fileName); 
        try {
            sw.WriteLine("# Unity terrain OBJ File");
            // Write vertices
            System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
            counter = tCount = 0;
            totalCount = (tVertices.Length * 2 + (saveFormat == SaveFormat.Triangles ? tPolys.Length / 3 : tPolys.Length / 4)) / progressUpdateInterval; 
            for (int i = 0; i < tVertices.Length; i++)
            {
                UpdateProgress(); 
                StringBuilder sb = new StringBuilder("v ", 20); 
                // StringBuilder stuff is done this way because it's faster than using the "{0} {1} {2}"etc. format 
                // Which is important when you're exporting huge terrains. 
                sb.Append(tVertices[i].x.ToString()).Append(" "). Append(tVertices[i].y.ToString()).Append(" "). Append(tVertices[i].z.ToString()); sw.WriteLine(sb);
            } 
            // Write UVs
            for (int i = 0; i < tUV.Length; i++) { 
                UpdateProgress(); 
                StringBuilder sb = new StringBuilder("vt ", 22);
                sb.Append(tUV[i].x.ToString()).Append(" "). Append(tUV[i].y.ToString()); sw.WriteLine(sb); } 
            if (saveFormat == SaveFormat.Triangles) 
            {
                // Write triangles
                for (int i = 0; i < tPolys.Length; i += 3) 
                {
                    UpdateProgress();
                    StringBuilder sb = new StringBuilder("f ", 43);
                    sb.Append(tPolys[i] + 1).Append("/").Append(tPolys[i] + 1).Append(" ").
                    Append(tPolys[i + 1] + 1).Append("/").Append(tPolys[i + 1] + 1).
                    Append(" "). Append(tPolys[i + 2] + 1).Append("/").Append(tPolys[i + 2] + 1); 
                    sw.WriteLine(sb);
            }
            } else { 
                // Write quads 
                for (int i = 0; i < tPolys.Length; i += 4) 
                    { 
                    UpdateProgress(); 
                    StringBuilder sb = new StringBuilder("f ", 57); 
                    sb.Append(tPolys[i] + 1).Append("/").Append(tPolys[i] + 1).Append(" "). 
                    Append(tPolys[i + 1] + 1).Append("/").Append(tPolys[i + 1] + 1).Append(" "). 
                    Append(tPolys[i + 2] + 1).Append("/").Append(tPolys[i + 2] + 1).Append(" ").
                    Append(tPolys[i + 3] + 1).Append("/").Append(tPolys[i + 3] + 1); sw.WriteLine(sb);
                }
            } 
        } catch(Exception err) 
        {
            Debug.Log("Error saving file: " + err.Message); 
        }
        sw.Close(); 
        terrain = null; 
        EditorUtility.DisplayProgressBar("Saving file to disc.", "This might take a while...", 1f); 
        EditorWindow.GetWindow<ExportTerrain>().Close(); EditorUtility.ClearProgressBar();
    } 
    void UpdateProgress() 
    { 
        if (counter++ == progressUpdateInterval) 
        { counter = 0; EditorUtility.DisplayProgressBar("Saving...", "", Mathf.InverseLerp(0, totalCount, ++tCount));
        } 
    } 
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章