Unity地形导出为.obj模型
在Uniyt 3D中创建的真实地形想保存为模型以备以后使用,经过在网上艰辛的搜索,终于找到一个方法,经过实验验证,绝对真实可靠!有图有真相!
源代码来自于这儿: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中打开是没有贴图的,需要重新为其附贴图。