天天看點

将Unity3D中的地形導出為*.Obj模型檔案

将下面的腳本放在你項目目錄下資源檔案夾的Editor裡.

要導出地形,首先在你的場景中選中地形對象.如果沒選,他将用于目前場景中可用的地 形.從Terrain菜單下選擇Export To Obj... ,在分辨率視窗,選擇你要四邊形還是三角形網格結構.同樣也可以選擇要導出地形的分辨率,有高中低等等.點選Export,選擇要儲存的位置和檔案 名.Obj檔案将被導出.要注意如果選擇大面積的Full地形導出,最終的Obj檔案将非常大,而且也要導出很久.

下面為 ExportTerrain.js腳本.

001 import System.IO;

002 import System.Text;

003

004 enum SaveFormat {Triangles, Quads}

005 enum SaveResolution {Full, Half, Quarter, Eighth, Sixteenth}

006

007 class ExportTerrain extends EditorWindow {

008 var saveFormat = SaveFormat.Triangles;

009 var saveResolution = SaveResolution.Half;

010 static var terrain : TerrainData;

011 static var terrainPos : Vector3;

012

013 var tCount : int;

014 var counter : int;

015 var totalCount : int;

016

017 @MenuItem ("Terrain/Export To Obj...")

018 static function Init () {

019 terrain = null;

020 var terrainObject : Terrain = Selection.activeObject as Terrain;

021 if (!terrainObject) {

022 terrainObject = Terrain.activeTerrain;

023 }

024 if (terrainObject) {

025 terrain = terrainObject.terrainData;

026 terrainPos = terrainObject.transform.position;

027 }

028 EditorWindow.GetWindow(ExportTerrain).Show();

029 }

030

031 function OnGUI () {

032 if (!terrain) {

033 GUILayout.Label("No terrain found");

034 if (GUILayout.Button("Cancel")) {

035 EditorWindow.GetWindow(ExportTerrain).Close();

036 }

037 return;

038 }

039 saveFormat = EditorGUILayout.EnumPopup("Export Format", saveFormat);

040 saveResolution = EditorGUILayout.EnumPopup("Resolution", saveResolution);

041

042 if (GUILayout.Button("Export")) {

043 Export();

044 }

045 }

046

047 function Export () {

048 var fileName = EditorUtility.SaveFilePanel("Export .obj file", "", "Terrain", "obj");

049 var w = terrain.heightmapWidth;

050 var h = terrain.heightmapHeight;

051 var meshScale = terrain.size;

052 var tRes = Mathf.Pow(2, parseInt(saveResolution));

053 meshScale = Vector3(meshScale.x/(w-1)*tRes, meshScale.y, meshScale.z/(h-1)*tRes);

054 var uvScale = Vector2(1.0/(w-1), 1.0/(h-1));

055 var tData = terrain.GetHeights(0, 0, w, h);

056

057 w = (w-1) / tRes + 1;

058 h = (h-1) / tRes + 1;

059 var tVertices = new Vector3[w * h];

060 var tUV = new Vector2[w * h];

061 if (saveFormat == SaveFormat.Triangles) {

062 var tPolys = new int[(w-1) * (h-1) * 6];

063 }

064 else {

065 tPolys = new int[(w-1) * (h-1) * 4];

066 }

067

068 // Build vertices and UVs

069 for (y = 0; y < h; y++) {

070 for (x = 0; x < w; x++) {

071 tVertices[y*w + x] = Vector3.Scale(meshScale, Vector3(x, tData[x*tRes,y*tRes], y)) + terrainPos;

072 tUV[y*w + x] = Vector2.Scale(Vector2(x*tRes, y*tRes), uvScale);

073 }

074 }

075

076 var index = 0;

077 if (saveFormat == SaveFormat.Triangles) {

078 // Build triangle indices: 3 indices into vertex array for each triangle

079 for (y = 0; y < h-1; y++) {

080 for (x = 0; x < w-1; x++) {

081 // For each grid cell output two triangles

082 tPolys[index++] = (y * w) + x;

083 tPolys[index++] = ((y+1) * w) + x;

084 tPolys[index++] = (y * w) + x + 1;

085

086 tPolys[index++] = ((y+1) * w) + x;

087 tPolys[index++] = ((y+1) * w) + x + 1;

088 tPolys[index++] = (y * w) + x + 1;

089 }

090 }

091 }

092 else {

093 // Build quad indices: 4 indices into vertex array for each quad

094 for (y = 0; y < h-1; y++) {

095 for (x = 0; x < w-1; x++) {

096 // For each grid cell output one quad

097 tPolys[index++] = (y * w) + x;

098 tPolys[index++] = ((y+1) * w) + x;

099 tPolys[index++] = ((y+1) * w) + x + 1;

100 tPolys[index++] = (y * w) + x + 1;

101 }

102 }

103 }

104

105 // Export to .obj

106 try {

107 var sw = new StreamWriter(fileName);

108 sw.WriteLine("# Unity terrain OBJ File");

109

110 // Write vertices

111 System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");

112 counter = tCount = 0;

113 totalCount = (tVertices.Length*2 + (saveFormat == SaveFormat.Triangles? tPolys.Length/3 : tPolys.Length/4)) / 1000;

114 for (i = 0; i < tVertices.Length; i++) {

115 UpdateProgress();

116 var sb = StringBuilder("v ", 20);

117 // StringBuilder stuff is done this way because it\'s faster than using the "{0} {1} {2}"etc. format

118 // Which is important when you\'re exporting huge terrains.

119 sb.Append(tVertices[i].x.ToString()).Append(" ").

120 Append(tVertices[i].y.ToString()).Append(" ").

121 Append(tVertices[i].z.ToString());

122 sw.WriteLine(sb);

123 }

124 // Write UVs

125 for (i = 0; i < tUV.Length; i++) {

126 UpdateProgress();

127 sb = StringBuilder("vt ", 22);

128 sb.Append(tUV[i].x.ToString()).Append(" ").

129 Append(tUV[i].y.ToString());

130 sw.WriteLine(sb);

131 }

132 if (saveFormat == SaveFormat.Triangles) {

133 // Write triangles

134 for (i = 0; i < tPolys.Length; i += 3) {

135 UpdateProgress();

136 sb = StringBuilder("f ", 43);

137 sb.Append(tPolys[i]+1).Append("/").Append(tPolys[i]+1).Append(" ").

138 Append(tPolys[i+1]+1).Append("/").Append(tPolys[i+1]+1).Append(" ").

139 Append(tPolys[i+2]+1).Append("/").Append(tPolys[i+2]+1);

140 sw.WriteLine(sb);

141 }

142 }

143 else {

144 // Write quads

145 for (i = 0; i < tPolys.Length; i += 4) {

146 UpdateProgress();

147 sb = StringBuilder("f ", 57);

148 sb.Append(tPolys[i]+1).Append("/").Append(tPolys[i]+1).Append(" ").

149 Append(tPolys[i+1]+1).Append("/").Append(tPolys[i+1]+1).Append(" ").

150 Append(tPolys[i+2]+1).Append("/").Append(tPolys[i+2]+1).Append(" ").

151 Append(tPolys[i+3]+1).Append("/").Append(tPolys[i+3]+1);

152 sw.WriteLine(sb);

153 }

154 }

155 }

156 catch (err) {

157 Debug.Log("Error saving file: " + err.Message);

158 }

159 sw.Close();

160

161 terrain = null;

162 EditorUtility.ClearProgressBar();

163 EditorWindow.GetWindow(ExportTerrain).Close();

164 }

165

166 function UpdateProgress () {

167 if (counter++ == 1000) {

168 counter = 0;

169 EditorUtility.DisplayProgressBar("Saving...", "", Mathf.InverseLerp(0, totalCount, ++tCount));

170 }

171 }

172 }