Unity地形匯出為.obj模型
阿新 • • 發佈:2019-02-07
我在Uniyt 3D中建立的真實地形想儲存為模型以備以後使用,經過在網上艱辛的搜尋(呵呵。。。),終於找到一個方法,經過實驗驗證,絕對真實可靠!有圖有真相!
先上程式碼(O(∩_∩)O哈哈~)。
原始碼來自於這兒:http://blog.sina.com.cn/s/blog_7812d64701010f7h.html,感謝他的分享!
下面為ExportTerrain.js指令碼:
import System.IO; import System.Text; enum SaveFormat {Triangles, Quads} enum SaveResolution {Full, Half, Quarter, Eighth, Sixteenth} class ExportTerrain extends EditorWindow { var saveFormat = SaveFormat.Triangles; var saveResolution = SaveResolution.Half; static var terrain : TerrainData; static var terrainPos : Vector3; var tCount : int; var counter : int; var totalCount : int; @MenuItem ("Terrain/Export To Obj...") static function Init () { terrain = null; var terrainObject : Terrain = Selection.activeObject as Terrain; if (!terrainObject) { terrainObject = Terrain.activeTerrain; } if (terrainObject) { terrain = terrainObject.terrainData; terrainPos = terrainObject.transform.position; } EditorWindow.GetWindow(ExportTerrain).Show(); } function OnGUI () { if (!terrain) { GUILayout.Label("No terrain found"); if (GUILayout.Button("Cancel")) { EditorWindow.GetWindow(ExportTerrain).Close(); } return; } saveFormat = EditorGUILayout.EnumPopup("Export Format", saveFormat); saveResolution = EditorGUILayout.EnumPopup("Resolution", saveResolution); if (GUILayout.Button("Export")) { Export(); } } function Export () { var fileName = EditorUtility.SaveFilePanel("Export .obj file", "", "Terrain", "obj"); var w = terrain.heightmapWidth; var h = terrain.heightmapHeight; var meshScale = terrain.size; var tRes = Mathf.Pow(2, parseInt(saveResolution)); meshScale = Vector3(meshScale.x/(w-1)*tRes, meshScale.y, meshScale.z/(h-1)*tRes); var uvScale = Vector2(1.0/(w-1), 1.0/(h-1)); var tData = terrain.GetHeights(0, 0, w, h); w = (w-1) / tRes + 1; h = (h-1) / tRes + 1; var tVertices = new Vector3[w * h]; var tUV = new Vector2[w * h]; if (saveFormat == SaveFormat.Triangles) { var tPolys = new int[(w-1) * (h-1) * 6]; } else { tPolys = new int[(w-1) * (h-1) * 4]; } // Build vertices and UVs for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { tVertices[y*w + x] = Vector3.Scale(meshScale, Vector3(x, tData[x*tRes,y*tRes], y)) + terrainPos; tUV[y*w + x] = Vector2.Scale(Vector2(x*tRes, y*tRes), uvScale); } } var index = 0; if (saveFormat == SaveFormat.Triangles) { // Build triangle indices: 3 indices into vertex array for each triangle for (y = 0; y < h-1; y++) { for (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 (y = 0; y < h-1; y++) { for (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 try { var sw = new StreamWriter(fileName); 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)) / 1000; for (i = 0; i < tVertices.Length; i++) { UpdateProgress(); var sb = 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 (i = 0; i < tUV.Length; i++) { UpdateProgress(); sb = 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 (i = 0; i < tPolys.Length; i += 3) { UpdateProgress(); sb = 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 (i = 0; i < tPolys.Length; i += 4) { UpdateProgress(); sb = 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 (err) { Debug.Log("Error saving file: " + err.Message); } sw.Close(); terrain = null; EditorUtility.ClearProgressBar(); EditorWindow.GetWindow(ExportTerrain).Close(); } function UpdateProgress () { if (counter++ == 1000) { counter = 0; EditorUtility.DisplayProgressBar("Saving...", "", Mathf.InverseLerp(0, totalCount, ++tCount)); } } }
將上面的指令碼放在Unity項的目錄資原始檔夾的Editor裡。
重新整理一下選單欄,會發現多了一個Terrain的選單。
先在場景中選中地形物件,如果沒選,他將用於當前場景中可用的地形。
然後從Terrain選單下選擇Export To Obj...
接下來會彈出一個框,在這裡你可以選擇要匯出四邊形網路結構還是三角形網路結構,還可以選擇要匯出的地形的解析度,有高中低...。最後點選Export,選擇要儲存的位置和檔名,.obj檔案將被匯出。
注意:如果選擇大面積的Full地形匯出,最終.obj檔案將非常大,而且也要匯出很久。
下邊是我實踐過的例子:
Uniyt 4.6.2中建立的真實地形(釣魚島哈):
匯出.obj格式的模型(模型和貼圖):
在Maya 2013中開啟如下:
哎呀,怎麼是這個樣子?我只想要釣魚島,該怎麼辦?只要在Maya裡簡單處理一下就好了。
選中模型,右鍵選擇“面”:
框選中模型整體,然後切換到側檢視,按著Shift鍵,用滑鼠框選突出的部分。(注意:要稍微比水平面高一點。)
Delete刪除,大功告成!
好啦,給他加上貼圖,匯出為FBX檔案,再放回Unity看看(釣魚島和達山島)。
PS:.obj模型在maya中開啟是沒有貼圖的,需要重新為其附貼圖。