Unity地形导出为.obj模型

我在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中打开是没有贴图的,需要重新为其附贴图。

 

  • 3
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值