在Unity中建立的场景文件,摆放的模型可以用下列脚本导出为Obj模型文件,可以保持场景中模型的位置,贴图灯信息.
将脚本命名为ObjExporter.cs,放在项目的Editor目录下,选择你要导出的模型物体(可以有若干子物体),在编辑器菜单中找到Custom的输出选项,能看到三个选项,分别是"输出所有网格到单一的Obj文件","输出选择的网格合体到一个Obj文件","输出每个选择的模型到单一Obj文件",一般常用第二项.成功输出后将弹出对话框,模型和关联的贴图将放到项目的根目录的"ExportedObj"文件夹中.
EditorObjExporter.cs脚本:
将脚本命名为ObjExporter.cs,放在项目的Editor目录下,选择你要导出的模型物体(可以有若干子物体),在编辑器菜单中找到Custom的输出选项,能看到三个选项,分别是"输出所有网格到单一的Obj文件","输出选择的网格合体到一个Obj文件","输出每个选择的模型到单一Obj文件",一般常用第二项.成功输出后将弹出对话框,模型和关联的贴图将放到项目的根目录的"ExportedObj"文件夹中.
EditorObjExporter.cs脚本:
using
UnityEngine;
using
UnityEditor;
using
System.Collections;
using
System.Collections.Generic;
using
System.IO;
using
System.Text;
using
System;
struct
ObjMaterial
{
public
string
name;
public
string
textureName;
}
public
class
EditorObjExporter : ScriptableObject
{
private
static
int
vertexOffset = 0;
private
static
int
normalOffset = 0;
private
static
int
uvOffset = 0;
//User should probably be able to change this. It is currently left as an excercise for
//the reader.
private
static
string
targetFolder =
"ExportedObj"
;
private
static
string
MeshToString(MeshFilter mf, Dictionary<
string
, ObjMaterial> materialList)
{
Mesh m = mf.sharedMesh;
Material[] mats = mf.renderer.sharedMaterials;
StringBuilder sb =
new
StringBuilder();
sb.Append(
"g "
).Append(mf.name).Append(
"\n"
);
foreach
(Vector3 lv
in
m.vertices)
{
Vector3 wv = mf.transform.TransformPoint(lv);
//This is sort of ugly - inverting x-component since we're in
//a different coordinate system than "everyone" is "used to".
sb.Append(
string
.Format(
"v {0} {1} {2}\n"
,-wv.x,wv.y,wv.z));
}
sb.Append(
"\n"
);
foreach
(Vector3 lv
in
m.normals)
{
Vector3 wv = mf.transform.TransformDirection(lv);
sb.Append(
string
.Format(
"vn {0} {1} {2}\n"
,-wv.x,wv.y,wv.z));
}
sb.Append(
"\n"
);
foreach
(Vector3 v
in
m.uv)
{
sb.Append(
string
.Format(
"vt {0} {1}\n"
,v.x,v.y));
}
for
(
int
material=0; material < m.subMeshCount; material ++) {
sb.Append(
"\n"
);
sb.Append(
"usemtl "
).Append(mats[material].name).Append(
"\n"
);
sb.Append(
"usemap "
).Append(mats[material].name).Append(
"\n"
);
//See if this material is already in the materiallist.
try
{
ObjMaterial objMaterial =
new
ObjMaterial();
objMaterial.name = mats[material].name;
if
(mats[material].mainTexture)
objMaterial.textureName = EditorUtility.GetAssetPath(mats[material].mainTexture);
else
objMaterial.textureName =
null
;
materialList.Add(objMaterial.name, objMaterial);
}
catch
(ArgumentException)
{
//Already in the dictionary
}
int
[] triangles = m.GetTriangles(material);
for
(
int
i=0;i<triangles.Length;i+=3)
{
//Because we inverted the x-component, we also needed to alter the triangle winding.
sb.Append(
string
.Format(
"f {1}/{1}/{1} {0}/{0}/{0} {2}/{2}/{2}\n"
,
triangles[i]+1 + vertexOffset, triangles[i+1]+1 + normalOffset, triangles[i+2]+1 + uvOffset));
}
}
vertexOffset += m.vertices.Length;
normalOffset += m.normals.Length;
uvOffset += m.uv.Length;
return
sb.ToString();
}
private
static
void
Clear()
{
vertexOffset = 0;
normalOffset = 0;
uvOffset = 0;
}
private
static
Dictionary<
string
, ObjMaterial> PrepareFileWrite()
{
Clear();
return
new
Dictionary<
string
, ObjMaterial>();
}
private
static
void
MaterialsToFile(Dictionary<
string
, ObjMaterial> materialList,
string
folder,
string
filename)
{
using
(StreamWriter sw =
new
StreamWriter(folder +
"/"
+ filename +
".mtl"
))
{
foreach
( KeyValuePair<
string
, ObjMaterial> kvp
in
materialList )
{
sw.Write(
"\n"
);
sw.Write(
"newmtl {0}\n"
, kvp.Key);
sw.Write(
"Ka 0.6 0.6 0.6\n"
);
sw.Write(
"Kd 0.6 0.6 0.6\n"
);
sw.Write(
"Ks 0.9 0.9 0.9\n"
);
sw.Write(
"d 1.0\n"
);
sw.Write(
"Ns 0.0\n"
);
sw.Write(
"illum 2\n"
);
if
(kvp.Value.textureName !=
null
)
{
string
destinationFile = kvp.Value.textureName;
int
stripIndex = destinationFile.LastIndexOf(
'/'
);
//FIXME: Should be Path.PathSeparator;
if
(stripIndex >= 0)
destinationFile = destinationFile.Substring(stripIndex + 1).Trim();
string
relativeFile = destinationFile;
destinationFile = folder +
"/"
+ destinationFile;
Debug.Log(
"Copying texture from "
+ kvp.Value.textureName +
" to "
+ destinationFile);
try
{
//Copy the source file
File.Copy(kvp.Value.textureName, destinationFile);
}
catch
{
}
sw.Write(
"map_Kd {0}"
, relativeFile);
}
sw.Write(
"\n\n\n"
);
}
}
}
private
static
void
MeshToFile(MeshFilter mf,
string
folder,
string
filename)
{
Dictionary<
string
, ObjMaterial> materialList = PrepareFileWrite();
using
(StreamWriter sw =
new
StreamWriter(folder +
"/"
+ filename +
".obj"
))
{
sw.Write(
"mtllib ./"
+ filename +
".mtl\n"
);
sw.Write(MeshToString(mf, materialList));
}
MaterialsToFile(materialList, folder, filename);
}
private
static
void
MeshesToFile(MeshFilter[] mf,
string
folder,
string
filename)
{
Dictionary<
string
, ObjMaterial> materialList = PrepareFileWrite();
using
(StreamWriter sw =
new
StreamWriter(folder +
"/"
+ filename +
".obj"
))
{
sw.Write(
"mtllib ./"
+ filename +
".mtl\n"
);
for
(
int
i = 0; i < mf.Length; i++)
{
sw.Write(MeshToString(mf[i], materialList));
}
}
MaterialsToFile(materialList, folder, filename);
}
private
static
bool
CreateTargetFolder()
{
try
{
System.IO.Directory.CreateDirectory(targetFolder);
}
catch
{
EditorUtility.DisplayDialog(
"Error!"
,
"Failed to create target folder!"
,
""
);
return
false
;
}
return
true
;
}
[MenuItem (
"Custom/Export/Export all MeshFilters in selection to separate OBJs"
)]
static
void
ExportSelectionToSeparate()
{
if
(!CreateTargetFolder())
return
;
Transform[] selection = Selection.GetTransforms(SelectionMode.Editable | SelectionMode.ExcludePrefab);
if
(selection.Length == 0)
{
EditorUtility.DisplayDialog(
"No source object selected!"
,
"Please select one or more target objects"
,
""
);
return
;
}
int
exportedObjects = 0;
for
(
int
i = 0; i < selection.Length; i++)
{
Component[] meshfilter = selection[i].GetComponentsInChildren(
typeof
(MeshFilter));
for
(
int
m = 0; m < meshfilter.Length; m++)
{
exportedObjects++;
MeshToFile((MeshFilter)meshfilter[m], targetFolder, selection[i].name +
"_"
+ i +
"_"
+ m);
}
}
if
(exportedObjects > 0)
EditorUtility.DisplayDialog(
"Objects exported"
,
"Exported "
+ exportedObjects +
" objects"
,
""
);
else
EditorUtility.DisplayDialog(
"Objects not exported"
,
"Make sure at least some of your selected objects have mesh filters!"
,
""
);
}
[MenuItem (
"Custom/Export/Export whole selection to single OBJ"
)]
static
void
ExportWholeSelectionToSingle()
{
if
(!CreateTargetFolder())
return
;
Transform[] selection = Selection.GetTransforms(SelectionMode.Editable | SelectionMode.ExcludePrefab);
if
(selection.Length == 0)
{
EditorUtility.DisplayDialog(
"No source object selected!"
,
"Please select one or more target objects"
,
""
);
return
;
}
int
exportedObjects = 0;
ArrayList mfList =
new
ArrayList();
for
(
int
i = 0; i < selection.Length; i++)
{
Component[] meshfilter = selection[i].GetComponentsInChildren(
typeof
(MeshFilter));
for
(
int
m = 0; m < meshfilter.Length; m++)
{
exportedObjects++;
mfList.Add(meshfilter[m]);
}
}
if
(exportedObjects > 0)
{
MeshFilter[] mf =
new
MeshFilter[mfList.Count];
for
(
int
i = 0; i < mfList.Count; i++)
{
mf[i] = (MeshFilter)mfList[i];
}
string
filename = EditorApplication.currentScene +
"_"
+ exportedObjects;
int
stripIndex = filename.LastIndexOf(
'/'
);
//FIXME: Should be Path.PathSeparator
if
(stripIndex >= 0)
filename = filename.Substring(stripIndex + 1).Trim();
MeshesToFile(mf, targetFolder, filename);
EditorUtility.DisplayDialog(
"Objects exported"
,
"Exported "
+ exportedObjects +
" objects to "
+ filename,
""
);
}
else
EditorUtility.DisplayDialog(
"Objects not exported"
,
"Make sure at least some of your selected objects have mesh filters!"
,
""
);
}
[MenuItem (
"Custom/Export/Export each selected to single OBJ"
)]
static
void
ExportEachSelectionToSingle()
{
if
(!CreateTargetFolder())
return
;
Transform[] selection = Selection.GetTransforms(SelectionMode.Editable | SelectionMode.ExcludePrefab);
if
(selection.Length == 0)
{
EditorUtility.DisplayDialog(
"No source object selected!"
,
"Please select one or more target objects"
,
""
);
return
;
}
int
exportedObjects = 0;
for
(
int
i = 0; i < selection.Length; i++)
{
Component[] meshfilter = selection[i].GetComponentsInChildren(
typeof
(MeshFilter));
MeshFilter[] mf =
new
MeshFilter[meshfilter.Length];
for
(
int
m = 0; m < meshfilter.Length; m++)
{
exportedObjects++;
mf[m] = (MeshFilter)meshfilter[m];
}
MeshesToFile(mf, targetFolder, selection[i].name +
"_"
+ i);
}
if
(exportedObjects > 0)
{
EditorUtility.DisplayDialog(
"Objects exported"
,
"Exported "
+ exportedObjects +
" objects"
,
""
);
}
else
EditorUtility.DisplayDialog(
"Objects not exported"
,
"Make sure at least some of your selected objects have mesh filters!"
,
""
);
}
}
|