将下面的脚本放在你项目目录下资源文件夹的Editor里.
要导出地形,首先在你的场景中选中地形对象.如果没选,他将用于当前场景中可用的地形.从Terrain菜单下选择Export To
Obj...
,在分辨率窗口,选择你要四边形还是三角形网格结构.同样也可以选择要导出地形的分辨率,有高中低等等.点击Export,选择要保存的位置和文件名.Obj文件将被导出.要注意如果选择大面积的Full地形导出,最终的Obj文件将非常大,而且也要导出很久.
下面为ExportTerrain.js脚本.
003 |
enum SaveFormat
{Triangles, Quads} |
004 |
enum SaveResolution
{Full, Half, Quarter, Eighth, Sixteenth} |
005 |
class ExportTerrain
extends EditorWindow { |
006 |
var
saveFormat =
SaveFormat.Triangles; |
007 |
var
saveResolution =
SaveResolution.Half; |
008 |
static
var terrain : TerrainData; |
009 |
static
var terrainPos : Vector3; |
013 |
var
totalCount : int; |
015 |
@MenuItem
( "Terrain/Export To
Obj..." ) |
016 |
static
function Init () { |
018 |
var
terrainObject : Terrain =
Selection.activeObject as Terrain; |
019 |
if
(!terrainObject) { |
020 |
terrainObject
= Terrain.activeTerrain; |
023 |
terrain
= terrainObject.terrainData; |
024 |
terrainPos
= terrainObject.transform.position; |
026 |
EditorWindow.GetWindow(ExportTerrain).Show(); |
031 |
GUILayout.Label( "No
terrain found" ); |
032 |
if
(GUILayout.Button( "Cancel" ))
{ |
033 |
EditorWindow.GetWindow(ExportTerrain).Close(); |
037 |
saveFormat
= EditorGUILayout.EnumPopup( "Export Format" , saveFormat); |
038 |
saveResolution
= EditorGUILayout.EnumPopup( "Resolution" ,
saveResolution); |
040 |
if
(GUILayout.Button( "Export" ))
{ |
046 |
var
fileName =
EditorUtility.SaveFilePanel( "Export .obj file" , "" ,
"Terrain" , "obj" ); |
047 |
var
w = terrain.heightmapWidth; |
048 |
var
h =
terrain.heightmapHeight; |
049 |
var
meshScale = terrain.size; |
050 |
var
tRes = Mathf.Pow(2,
parseInt(saveResolution)); |
051 |
meshScale
= Vector3(meshScale.x/(w-1)*tRes, meshScale.y,
meshScale.z/(h-1)*tRes); |
052 |
var
uvScale = Vector2(1.0/(w-1),
1.0/(h-1)); |
053 |
var
tData = terrain.GetHeights(0, 0, w,
h); |
055 |
w
= (w-1) / tRes + 1; |
056 |
h
= (h-1) / tRes + 1; |
057 |
var
tVertices = new Vector3[w
* h]; |
058 |
var
tUV = new Vector2[w
* h]; |
059 |
if
(saveFormat == SaveFormat.Triangles)
{ |
060 |
var
tPolys = new int[(w-1)
* (h-1) * 6]; |
063 |
tPolys
= new int[(w-1) * (h-1) * 4]; |
066 |
//
Build vertices and UVs |
067 |
for
(y = 0; y < h; y++)
{ |
068 |
for
(x = 0; x < w; x++)
{ |
069 |
tVertices[y*w
+ x] = Vector3.Scale(meshScale, Vector3(x, tData[x*tRes,y*tRes],
y)) + terrainPos; |
070 |
tUV[y*w
+ x] = Vector2.Scale(Vector2(x*tRes, y*tRes), uvScale); |
075 |
if
(saveFormat == SaveFormat.Triangles)
{ |
076 |
//
Build triangle indices: 3 indices into vertex array for each
triangle |
077 |
for
(y = 0; y < h-1; y++)
{ |
078 |
for
(x = 0; x < w-1; x++)
{ |
079 |
//
For each grid cell output two triangles |
080 |
tPolys[index++]
=
(y
* w) + x; |
081 |
tPolys[index++]
= ((y+1) * w) + x; |
082 |
tPolys[index++]
=
(y
* w) + x + 1; |
084 |
tPolys[index++]
= ((y+1) * w) + x; |
085 |
tPolys[index++]
= ((y+1) * w) + x + 1; |
086 |
tPolys[index++]
=
(y
* w) + x + 1; |
091 |
//
Build quad indices: 4 indices into vertex array for each
quad |
092 |
for
(y = 0; y < h-1; y++)
{ |
093 |
for
(x = 0; x < w-1; x++)
{ |
094 |
//
For each grid cell output one quad |
095 |
tPolys[index++]
=
(y
* w) + x; |
096 |
tPolys[index++]
= ((y+1) * w) + x; |
097 |
tPolys[index++]
= ((y+1) * w) + x + 1; |
098 |
tPolys[index++]
=
(y
* w) + x + 1; |
105 |
var
sw = new StreamWriter(fileName); |
106 |
sw.WriteLine( "#
Unity terrain OBJ File" ); |
109 |
System.Threading.Thread.CurrentThread.CurrentCulture
= new System.Globalization.CultureInfo( "en-US" ); |
110 |
counter
= tCount = 0; |
111 |
totalCount
= (tVertices.Length*2 + (saveFormat == SaveFormat.Triangles?
tPolys.Length/3 : tPolys.Length/4)) / 1000; |
112 |
for
(i = 0; i <
tVertices.Length; i++) { |
114 |
var
sb = StringBuilder( "v " ,
20); |
115 |
//
StringBuilder stuff is done this way because it's faster than using
the "{0} {1} {2}"etc. format |
116 |
//
Which is important when you're exporting huge terrains. |
117 |
sb.Append(tVertices[i].x.ToString()).Append( "
" ). |
118 |
Append(tVertices[i].y.ToString()).Append( "
" ). |
119 |
Append(tVertices[i].z.ToString()); |
123 |
for
(i = 0; i < tUV.Length;
i++) { |
125 |
sb
= StringBuilder( "vt
" , 22); |
126 |
sb.Append(tUV[i].x.ToString()).Append( "
" ). |
127 |
Append(tUV[i].y.ToString()); |
130 |
if
(saveFormat == SaveFormat.Triangles)
{ |
132 |
for
(i = 0; i <
tPolys.Length; i += 3) { |
134 |
sb
= StringBuilder( "f
" , 43); |
135 |
sb.Append(tPolys[i]+1).Append( "/" ).Append(tPolys[i]+1).Append( "
" ). |
136 |
Append(tPolys[i+1]+1).Append( "/" ).Append(tPolys[i+1]+1).Append( "
" ). |
137 |
Append(tPolys[i+2]+1).Append( "/" ).Append(tPolys[i+2]+1); |
143 |
for
(i = 0; i <
tPolys.Length; i += 4) { |
145 |
sb
= StringBuilder( "f
" , 57); |
146 |
sb.Append(tPolys[i]+1).Append( "/" ).Append(tPolys[i]+1).Append( "
" ). |
147 |
Append(tPolys[i+1]+1).Append( "/" ).Append(tPolys[i+1]+1).Append( "
" ). |
148 |
Append(tPolys[i+2]+1).Append( "/" ).Append(tPolys[i+2]+1).Append( "
" ). |
149 |
Append(tPolys[i+3]+1).Append( "/" ).Append(tPolys[i+3]+1); |
155 |
Debug.Log( "Error
saving file: " +
err.Message); |
160 |
EditorUtility.ClearProgressBar(); |
161 |
EditorWindow.GetWindow(ExportTerrain).Close(); |
164 |
function
UpdateProgress () { |
165 |
if
(counter++ == 1000) { |
167 |
EditorUtility.DisplayProgressBar( "Saving..." ,
"" ,
Mathf.InverseLerp(0, totalCount, ++tCount)); |
加载中,请稍候......