感觉3ds Max SDK实在是博大精深,初学者入门还是很不方便,所以觉得以前发的心得应该得到补充,因而写了这样一个导出程序介绍,还是抱着学习的态度,不过还是希望能够对大家有所帮助。
想想研究3D MAX 的SDK已经有了不短的时间,真正算起来也有两个月了吧,但是讲到收获,确实不大。作为一个3D MAX二次开发的学习者,我首先学习了导出插件的编写,网上有很多参考资料,写的都差不多,可是都是写到关键的地方或者说比较模糊的地方就说不清楚了,今天我就结合自己所做的工作来讲讲3D MAX导出插件的编写心得。
环境配置:
步骤1.首先你得有VS2005,3ds Max 9,如果有就好办了,否则想办法搞到手吧,在中国做到这点应该不难。至于其他相近版本的IDE和MAX,情况基本类似。
步骤2.在3ds Max9 SDK"maxsdk"howto"3dsmaxPluginWizard中有个readme.txt,它会向你介绍如何配置3ds Max9 plugin的向导。
步骤3.启动vs2005,新建Visual C++项目,如果在右侧的模板组中能够找到”3dsmaxPluginWizard”,并且选择后能够弹出欢迎界面,说面配置已经成功了。
首先,需要做好如下的准备工作:
1. 安装一个完整版本的3D MAX与Visual Stdio。
我安装的是3D MAX 2009,最好是找一个完整的版本,因为完整的版本中有很多的学习资料与sdk供学习,很省事。3D MAX的二次开发对VS的要求是有一个对应关系的,在SDK文档中可以找到,3D MAX 2009对应的VS开发版本应该是VS 2005,确保电脑上已经安装了VS 2005。
2.定制3D MAX plug-in向导。
a.找到安装目录的3dsmaxPluginWizard文件夹(我的安装目录是C:\Program Files\Autodesk\3ds Max 9 SDK\maxsdk\howto\3dsmaxPluginWizard
),
b.打开此目录下的MaxPluginWizard.vsz 文件,编辑ABSOLUTE PATH参数为:
Param="ABSOLUTE_PATH=C:\Program Files\Autodesk\3ds Max 9\SDK\maxsdk\howto\3dsmaxPluginWizard"
c.将3dsmaxPluginWizard文件夹下的三个文件3dsmaxPluginWizard.ico、3dsmaxPluginWizard.vsdir、3dsmaxPluginWizard.vsz拷贝到VS 2005安装目录的 VC Projects 目录下,我电脑上的目录是C:\Program Files\Microsoft Visual Studio 8\VC\vcprojects。
d.启动VS 2005,File-New Project,选择Visual C++就可以看到3ds max Plugin Wizard选项,说明定制成功。
以上只是开发前的一些准备工作,都可以直接在3D MAX SDK的文档中直接找到,不过文档可都是英文的哦,要耐心的读下去。
在以上准备工作做好以后,就可以开始开发一个插件了,由简单到复杂,先做一个简单的插件程序。插件程序的编写有两种方法,一是用插件向导,就是刚才上面所说的;另一种是通过手工创建一个插件项目,在这里暂时只讨论用插件向导来开发,比较便捷,手工开发以后在补上。
1.第一步,生成一个插件程序的工程,具体如下:
a. 打开File —>New Project —>选择3ds max Plugin Wizard,输入project名字,如 “MyExport”。
b. 进入Welcome to the 3ds max Plugin Wizard 画面,选择plugin type如图所示:
c.这里显示各种插件类型,目前要做的是一个文件的导出插件,所以选择FileExport类型。
d.下一步,再出现一个对话框
不用去管这些Plugin Detail,会有默认路径的,。
e.再下一步,设置一些路径,具体见图及注明。
注明:
Enter your MAXSDK path指的是3D MAX SDK的安装目录
Enter your Plugin output path 指的是生成插件文件.dll存放的目录,可以自己设置
Enter your 3dsmax.exe path指的是3D MAX的安装目录
2.项目生成以后,在MyExport.cpp文件中找到Ext(int n)函数,改为return _T("MY3D"), "MY3D"是根据自己的要求来添加的;
找到ShortDesc()函数,改为return _T ("MyExportPlugin");
找到DoExport(const TCHAR *name,ExpInterface *ei,Interface *i, BOOL suppressPrompts, DWORD options)内添加:
AllocConsole();
_cprintf( "Export Begin\n" );//记得#include <conio.h>
3. 生成并调试你的插件,系统会执行3dsmax.exe以启动3ds Max,然后选择“文件”->”导出”,如果能看到"MyExportPlugin(*.My3D)"
说明导出成功,然后定义一个导出文件的名称即可.这样一个空的导出插件就编写成功了!接下来请看: 3D MAX导出插件编写II
Export利器:IGame
古人云:君子生非异也,善假于物也
数据导出是一个繁琐的工作,于是,有了IGame这个解脱程序员的东西:
关于IGame
IGame是Max提供给游戏开发的一个用于导入导出的接口。在Max的help里面这个东西叫做3ds Max Data Exchange Interface。有了这个接口,可以大大的简化导入导出工作的工作量。
如果有经历过用MAX SDK导出关键帧动画以及骨骼动画,Skin,Modifier等等的经历的话,我想肯定会记忆深刻。IGame的作用就是把复杂的Max的概念简化,封装。
建立IGame:
IGameScene * m_pIgame= GetIGameInterface()
坐标系:
前面我提到的导出的文章都没有提这个问题,所有的坐标都是用的MAX本身的坐标系,及Z轴向上。在游戏中坐标系可能千奇百怪,IGame考虑到这点提供了指定坐标系的功能:
IGameConversionManager * cm = GetConversionManager();
cm->SetCoordSystem(IGameConversionManager::IGAME_D3D);
m_pIgame->InitialiseIGame(true);
其中IGAME_D3D就是指定的坐标系,同样也可以自定义坐标系:
UserCoord WhackySystem = {
1, //Right Handed
1, //X axis goes right
4, //Y Axis goes in
3, //Z Axis goes down.
0, //U Tex axis is left
1, //V Tex axis is Down
};
IGameConversionManager * cm = GetConversionManager();
cm->SetUserCoordSystem(WhackySystem);
IGame要点:
GetTopLevelNodeCount:获得顶级的Node数目,不包括Root。
GetRootMaterialCount:获得所有的材质数目
GetTopLevelNode(i):获得指定Node
GetIGameObject():获得Node中包含的Object
GetLocalTM():获得Node的矩阵
IGameMesh ::GetVertex(i):获得顶点
IGameMesh ::GetFace(i);获得面
IGameMesh ::GetNormal(i):获得法线
至于其他就依次类推了,从函数的命名,到概念的简化,无疑都比原始的MAXSDK进步了很多。有了IGame接口,大大减轻了程序员的负担,我相信没有哪个愿意把大把的时间花在数据的导入导出上。
花了几十分钟简单的试用了一下IGame写了个小小的导出插件,只导出了顶点,面,材质,法线以及矩阵,感觉基本上没什么阻碍。不过IGame最大的功能还是用在骨骼动画,关键帧动画上面,仅仅只是简单的几何体导出并不能体现出IGame的功效。
最后还是附上代码和工程吧。不得不提示一下,由于种种曲折的原因,我这个工程是在MAX8 SDK和 MAX8下 完成的,其间省略上千字曲折的经历,不过在MAX9下应该可以通过编译。编译完成后,记得在Max 中选择Export Selected而不是试用Export。
3DS MAX PlugIn 材质和纹理 材质和纹理的信息都位于node 中
材质的信息通过类Mtl获得
纹理的信息位于node中的mesh 中的UVVert
以下是获得材质的代码:
//////////////////////////////////////////////////////////////////////////
//material
Mtl* nodematerial=node->GetMtl();
if(nodematerial)
{
fprintf(m_fileStream, "%s mtl -- name:<%s>\n", GetIndent(indent),nodematerial->GetName());
}
else
{
DWORD vcolor=node->GetWireColor();
fprintf(m_fileStream,"%s color -- rgb:<%d,%d,%d>\n", GetIndent(indent),GetRValue(vcolor), GetGValue(vcolor), GetBValue(vcolor));
}
//////////////////////////////////////////////////////////////////////////
以下是获取UV的代码,需要注意的是,需要对是否有多重贴图处理:
void OnlyGeometry::ExportUVInfo(Mesh* mesh,int indent)
{
int numTVerts = mesh->getNumTVerts();
if(numTVerts>0)
{
fprintf(m_fileStream, "%s texture channel 1 -- numverts:<%d>\n", GetIndent(indent),numTVerts);
for (int i = 0; i < numTVerts; i++)
{
UVVert tvert = mesh->tVerts[i];
fprintf(m_fileStream, "%s UVW tvert %d:<%f,%f,%f>\n", GetIndent(indent),i, tvert.x, tvert.y, tvert.z);
}
// print tvert indices used by tvfaces
for (int i = 0; i < mesh->getNumFaces(); i++)
{
TVFace tface = mesh->tvFace[i];
fprintf(m_fileStream, "%s TVFace %d -- tvertind:<%d,%d,%d>\n",
GetIndent(indent),i, tface.t[0], tface.t[1], tface.t[2]);
}
}
//多重贴图
for (int chanloop = 2; chanloop < MAX_MESHMAPS - 1; chanloop++)
{
if (mesh->mapSupport(chanloop))
{
numTVerts = mesh->getNumMapVerts(chanloop);
fprintf(m_fileStream, "%s texture channel %d -- numverts:<%d>\n", GetIndent(indent),chanloop, numTVerts);
for (int i = 0; i < numTVerts; i++)
{
UVVert tvert = mesh->mapVerts(chanloop)[i];
fprintf(m_fileStream, "%s UVW tvert %d:<%f,%f,%f>\n", GetIndent(indent),i, tvert.x, tvert.y, tvert.z);
}
// now, print tvert indices used by tvfaces
for (int i = 0; i < mesh->getNumFaces(); i++)
{
TVFace tface = mesh->mapFaces(chanloop)[i];
fprintf(m_fileStream, "%s TVFace %d -- tvertind:<%d,%d,%d>\n", GetIndent(indent),
i, tface.t[0], tface.t[1], tface.t[2]);
}
}
}
}
从简单开始 邂逅Geometry
Download[onlygeometry.rar]
几何体的导出是相当容易的,有了上次获得Node的基础,获得几何体的信息就显得顺其自然了。
几何体关心的主要信息就是顶点和三角面,自然还有纹理坐标,法线,顶点颜色,切线,BinNormal等等,不过这些都是后话,首先我们只关心顶点和面。
同时另外一个重要的信息就是矩阵信息,需要注意的是,在不同的Frame中矩阵信息很可能会发生变化,这点需要注意下。
在第一个例子的基础上 只需要添加为数不多的代码即可实现。
首先我们需要判断结点是不是包含几何体信息:
BOOL OnlyGeometry::nodeEnum(INode* node,int indent)
{
……
ObjectState os = node->EvalWorldState(m_ip->GetTime());
if (os.obj)
{
if(os.obj->SuperClassID()==GEOMOBJECT_CLASS_ID)
{
ExportGeomObject(node,indent);
}
}
for (int c = 0; c < node->NumberOfChildren(); c++) {
if (!nodeEnum(node->GetChildNode(c),indent+1))
return FALSE;
}
return TRUE;
}
然后在具体的导出几何体的函数中,我们还需要再判断一次:
void OnlyGeometry::ExportGeomObject(INode* node,int indent)
{
TimeValue time= m_ip->GetTime();
ObjectState os=node->EvalWorldState(time);
if(!os.obj)
return;
if (os.obj->ClassID() == Class_ID(TARGET_CLASS_ID, 0))
return;
…………………..
这是因为在3DS MAX中还有很多其他的物体也包含了几何体信息,例如相机和灯光的Target部分,所以需要过滤一下。
然后就直接获取我们需要的信息,首先是矩阵:我们使用
INode:: GetObjectTMAfterWSM()来获得。这里WSM是World Space Modifier的缩写。意思是在使用了World Space Modifier之后的矩阵。关于World Space Modifier的详细信息可以参看SDK的文档,因为本例中没有用到任何的World Space Modifier。所以这里如果使用INode::GetObjectTM()的效果也是一样的。
Matrix3 tm=node->GetObjTMAfterWSM(time);
Point3 row=tm.GetRow(0);
fprintf(m_fileStream,"%s%s<%f %f %f>\n",GetIndent(indent),_T("Matrix Row 0:"),row.x,row.y,row.z);
row=tm.GetRow(1);
fprintf(m_fileStream,"%s%s<%f %f %f>\n",GetIndent(indent),_T("Matrix Row 1:"),row.x,row.y,row.z);
row=tm.GetRow(2);
fprintf(m_fileStream,"%s%s<%f %f %f>\n",GetIndent(indent),_T("Matrix Row 2:"),row.x,row.y,row.z);
row=tm.GetRow(3);
fprintf(m_fileStream,"%s%s<%f %f %f>\n",GetIndent(indent),_T("Matrix Row 3:"),row.x,row.y,row.z);
接下来就是顶点和三角面的导出,在Max中的结点并没有直接保存了Mesh的信息,我们如果要获得Mesh的信息需要首先将Object转化为Mesh,然后再从Mesh获得具体的信息:
TriObject* triobj=0;
triobj=(TriObject*)os.obj->ConvertToType(time,Class_ID(TRIOBJ_CLASS_ID,0));
这里Max给我们执行的其实是一个Deep Copy,所以我们可以等会转换完成后把内存释放。
if(triobj!=os.obj) //deep copy
{
Mesh * mesh = &(triobj->GetMesh());
if(mesh)
{
mesh->buildNormals();
fprintf(m_fileStream,"%s%s\n",GetIndent(indent),_T("Geometry Data:"));
fprintf(m_fileStream,"%s%s%d%s%d\n",GetIndent(indent+1),_T("Vertex Number:"),mesh->getNumVerts(),_T("Face Number:"),mesh->getNumFaces());
//顶点信息
for(int i=0;i<mesh->getNumVerts();++i)
{
Point3 vert = tm * mesh->verts[i];
fprintf(m_fileStream, "%s vertex %d:<%f,%f,%f>\n", GetIndent(indent),i, vert.x, vert.y, vert.z);
}
//面信息
for (int i = 0; i < mesh->getNumFaces(); i++)
{
fprintf(m_fileStream, "%s face %d -- verts:<%d,%d,%d> edgevis:<%d,%d,%d> smoothgrp:<0x%x> matid:<%d>\n",
GetIndent(indent),
i,
mesh->faces[i].v[0],
mesh->faces[i].v[1],
mesh->faces[i].v[2],
mesh->faces[i].getEdgeVis(0) ? 1 : 0,
mesh->faces[i].getEdgeVis(1) ? 1 : 0,
mesh->faces[i].getEdgeVis(2) ? 1 : 0,
mesh->faces[i].getSmGroup(),
mesh->faces[i].getMatID());
}
}
}
delete triobj;
fprintf(m_fileStream,"%s%s\n",GetIndent(indent),_T("Geometry End"));
fprintf(m_fileStream, "\n");
}
到此为止,我们的初步导出Geometry的工作就顺利完成了,可以打开Max试一试,输出的简单的文件如下:
Begin Do Header
Begin Do Nodes
Totoal Node Number:3
Root Name:Scene Root
Node Name:Box01
Matrix Row 0:<1.000000 0.000000 0.000000>
Matrix Row 1:<0.000000 1.000000 0.000000>
Matrix Row 2:<0.000000 0.000000 1.000000>
Matrix Row 3:<-19.448299 -3.523636 0.000000>
Geometry Data:
Vertex Number:8Face Number:12
vertex 0:<-40.204018,-28.128052,0.000000>
vertex 1:<1.307419,-28.128052,0.000000>
vertex 2:<-40.204018,21.080780,0.000000>
vertex 3:<1.307419,21.080780,0.000000>
vertex 4:<-40.204018,-28.128052,24.273842>
vertex 5:<1.307419,-28.128052,24.273842>
vertex 6:<-40.204018,21.080780,24.273842>
vertex 7:<1.307419,21.080780,24.273842>
face 0 -- verts:<0,2,3> edgevis:<1,1,0> smoothgrp:<0x2> matid:<1>
face 1 -- verts:<3,1,0> edgevis:<1,1,0> smoothgrp:<0x2> matid:<1>
face 2 -- verts:<4,5,7> edgevis:<1,1,0> smoothgrp:<0x4> matid:<0>
face 3 -- verts:<7,6,4> edgevis:<1,1,0> smoothgrp:<0x4> matid:<0>
face 4 -- verts:<0,1,5> edgevis:<1,1,0> smoothgrp:<0x8> matid:<4>
face 5 -- verts:<5,4,0> edgevis:<1,1,0> smoothgrp:<0x8> matid:<4>
face 6 -- verts:<1,3,7> edgevis:<1,1,0> smoothgrp:<0x10> matid:<3>
face 7 -- verts:<7,5,1> edgevis:<1,1,0> smoothgrp:<0x10> matid:<3>
face 8 -- verts:<3,2,6> edgevis:<1,1,0> smoothgrp:<0x20> matid:<5>
face 9 -- verts:<6,7,3> edgevis:<1,1,0> smoothgrp:<0x20> matid:<5>
face 10 -- verts:<2,0,4> edgevis:<1,1,0> smoothgrp:<0x40> matid:<2>
face 11 -- verts:<4,6,2> edgevis:<1,1,0> smoothgrp:<0x40> matid:<2>
Geometry End
Node Name:Pyramid01
Matrix Row 0:<1.000000 0.000000 0.000000>
Matrix Row 1:<0.000000 1.000000 0.000000>
Matrix Row 2:<0.000000 0.000000 1.000000>
Matrix Row 3:<24.578979 -52.777748 0.005000>
Geometry Data:
Vertex Number:6Face Number:8
vertex 0:<24.578979,-52.777748,43.850536>
vertex 1:<-1.593857,-72.522881,0.005000>
vertex 2:<50.751816,-72.522881,0.005000>
vertex 3:<50.751816,-33.032616,0.005000>
vertex 4:<-1.593857,-33.032616,0.005000>
vertex 5:<24.578979,-52.777748,0.005000>
face 0 -- verts:<0,1,2> edgevis:<1,1,1> smoothgrp:<0x4> matid:<0>
face 1 -- verts:<0,2,3> edgevis:<1,1,1> smoothgrp:<0x2> matid:<0>
face 2 -- verts:<0,3,4> edgevis:<1,1,1> smoothgrp:<0x10> matid:<0>
face 3 -- verts:<0,4,1> edgevis:<1,1,1> smoothgrp:<0x20> matid:<0>
face 4 -- verts:<1,5,2> edgevis:<1,1,1> smoothgrp:<0x8> matid:<0>
face 5 -- verts:<2,5,3> edgevis:<1,1,1> smoothgrp:<0x8> matid:<0>
face 6 -- verts:<3,5,4> edgevis:<1,1,1> smoothgrp:<0x8> matid:<0>
face 7 -- verts:<4,5,1> edgevis:<1,1,1> smoothgrp:<0x8> matid:<0>
Geometry End
Node Name:Box02
Matrix Row 0:<1.000000 0.000000 0.000000>
Matrix Row 1:<0.000000 1.000000 0.000000>
Matrix Row 2:<0.000000 0.000000 1.000000>
Matrix Row 3:<128.516830 57.409515 0.000000>
Geometry Data:
Vertex Number:8Face Number:12
vertex 0:<111.216064,37.396194,0.000000>
vertex 1:<145.817596,37.396194,0.000000>
vertex 2:<111.216064,77.422836,0.000000>
vertex 3:<145.817596,77.422836,0.000000>
vertex 4:<111.216064,37.396194,-40.238293>
vertex 5:<145.817596,37.396194,-40.238293>
vertex 6:<111.216064,77.422836,-40.238293>
vertex 7:<145.817596,77.422836,-40.238293>
face 0 -- verts:<2,0,3> edgevis:<1,0,1> smoothgrp:<0x2> matid:<0>
face 1 -- verts:<1,3,0> edgevis:<1,0,1> smoothgrp:<0x2> matid:<0>
face 2 -- verts:<5,4,7> edgevis:<1,0,1> smoothgrp:<0x4> matid:<1>
face 3 -- verts:<6,7,4> edgevis:<1,0,1> smoothgrp:<0x4> matid:<1>
face 4 -- verts:<1,0,5> edgevis:<1,0,1> smoothgrp:<0x8> matid:<4>
face 5 -- verts:<4,5,0> edgevis:<1,0,1> smoothgrp:<0x8> matid:<4>
face 6 -- verts:<3,1,7> edgevis:<1,0,1> smoothgrp:<0x10> matid:<3>
face 7 -- verts:<5,7,1> edgevis:<1,0,1> smoothgrp:<0x10> matid:<3>
face 8 -- verts:<2,3,6> edgevis:<1,0,1> smoothgrp:<0x20> matid:<5>
face 9 -- verts:<7,6,3> edgevis:<1,0,1> smoothgrp:<0x20> matid:<5>
face 10 -- verts:<0,2,4> edgevis:<1,0,1> smoothgrp:<0x40> matid:<2>
face 11 -- verts:<6,4,2> edgevis:<1,0,1> smoothgrp:<0x40> matid:<2>
Geometry End
END MYEXPORTER
MAX Script Export/Import
2个工作日
写了一套简单的Export/Import插件
一直对MAX的 Script感到很好奇
说说使用的感受吧。
首先,如果要使用这套Script那么 首先会陷入到庞大的MAX的概念的汪洋大海之中
MAX中很多概念不同于平常熟知的 RealTime里面的思想
例如,MAX中的纹理坐标,每个顶点都有一对UV 这个很正常
但是同时 MAX对每个Face也保存了UV,这是因为MAX中的 每个Face都有可能是不同的贴图
等等
第二,如果熟悉了MAX中的哪些类能够干什么 那么Script也就是很水道渠成的事情了。为了写这2个插件,MAX Script 的help翻了无数次,几乎每写一句就要去翻一次。
第三,MAX中的数组起位置是1,但是MAX中有的概念 使用数组表示的时候起始位置为0 ,例如纹理的Channel,起始就是为0,并且Channel0 很危险,写入错误直接让MAX挂掉
第四,脚本编写很考验打字的准确度,由于变量没有类型,不需要声明就可以试用,打错一个字母的话那就查吧,运气不好的话,会让你疯掉的,同时MAX的脚本编辑器 超级难用。
第五,编写导入插件的时候,发现Script 中读入数据异常痛苦,我在Script的帮助中没有发现任何类似c语言中的fprintf(%...)的东西,只有通过脚本提供的skiptostring来做。
第六 Max Script的函数 没有明确的返回值的概念,不习惯
第七 那个调试器 太难用了,我打了无数个messagebox
总结:对于导入导出插件来说其实用SDK和Script 编写其实差别不大,因为都只是涉及到数据的读取和写入,并不涉及到复杂的逻辑。如果编写渲染类型或者是动画控制类型的插件 我觉得还是用script好一些,因为可以直接在MAX中看到结果,同时还能够一句一句的执行,很方便。
我只是初学,希望有经验的人给点经验,最后附上简单的插件代码,
导出插件只能到处一个几何体,点击ExportGeo按钮,然后点选几何体,即可输出
导入插件没什么特别的操作,导入插件结尾有些仓促
以下是导入插件:其实导入插件没什么必要写,反正是在MAX中建模,直接保存为MAX文件就可以了,这里
纯属练手
macroScript ImportGeo category: "HowTo2"
(
--从文件中读入某个分割符 后面 的数据
--FileStream:文件句柄
--needload :储存读取后的值的变量 (string or value)
--spliter:分隔符(string)
--bReadLine: 是否读取分隔符后所有的数据 1表示读取后面所有
fn LoadData FileStream spliter bReadLine=
(
temp=skiptostring FileStream spliter
if bReadLine==1 then
needload=readline FileStream
else
needload=readvalue FileStream
)
--***************************************************
--******************************************************
--****************************************************
vert_array = #()
face_array = #()
sgroup_array = #()
matid_array = #()
edge_array = #()
tm_row1=#()
tm_row2=#()
tm_row3=#()
tm_row4=#()
nodename=""
--以下均为material变量
_Material_Name
_Material_Type
_Material_Ambient
_Material_Diffuse
_Material_Specular
_Material_Specular_Lv
_Material_Glossiness
_Material_SelfillumColor
_Material_SelfillumAmount
_Material_DiffTexPath
BitmapPath
channel_num
UVW_Ver_Num
UVW_Face_Num
Vert_UV=#() --所有的顶点的uv都放在这里
Face_UV=#() --所有的面的uv都放在这里
Vert_UV_Size=#() --用于记录每个channel的顶点的uv总数
Face_UV_Size=#() --用语及了每个channel的面uv总数
in_name=getopenfilename()
if in_name!=undefined then
(
in_file=openfile in_name
if in_file!=undefined then
(
--node name
temp= readline in_file
token=filterString temp " "
nodename=(token[token.count] as string)
--**************************************************
--material info
_Material_Name=LoadData in_file "->" 1
_Material_Type=LoadData in_file "->" 1
_Material_Ambient=LoadData in_file "->" 0
_Material_Diffuse=LoadData in_file "->" 0
_Material_Specular=LoadData in_file "->" 0
_Material_Specular_Lv=LoadData in_file "->" 0
_Material_Glossiness=LoadData in_file "->" 0
_Material_SelfillumColor=LoadData in_file "->" 0
_Material_SelfillumAmount=LoadData in_file "->" 0
_Material_DiffTexPath=LoadData in_file "->" 1
--**************************************************
--node matrix
--temp= readline in_file
tt=readDelimitedString in_file ":"
temp=readvalue in_file
append tm_row1(temp)
tt=readDelimitedString in_file ":"
temp=readvalue in_file
append tm_row2(temp)
tt=readDelimitedString in_file ":"
temp=readvalue in_file
append tm_row3(temp)
tt=readDelimitedString in_file ":"
temp=readvalue in_file
append tm_row4(temp)
--************************************************
--vertex info
temp= readline in_file
token=filterString temp " "
num_vert=token[token.count] as integer
for i=1 to num_vert do
(
tt=readDelimitedString in_file ":"
temp=readvalue in_file
append vert_array (temp)
)
--************************************************************
--face info
temp=readline in_file
token=filterstring temp " "
num_face=(token[token.count] as integer)
for j=1 to num_face do
(
append face_array (readValue in_file)
append sgroup_array (readValue in_file)
append matid_array (readValue in_file)
edge1 = readValue in_file
edge2 = readValue in_file
edge3 = readValue in_file
append edge_array (#(edge1, edge2, edge3))
)
--************************************************************
--uv info
-- in max channel begin with 0
--the channel 0 stores the vertex color info,no uv info
channel_num=LoadData in_file ":" 0
for b=1 to (channel_num-1) do
(
--读出Channel id
channel_id=LoadData in_file ":" 0
--texture map path
BitmapPath=LoadData in_file "->" 1
--读出uv Vertex 的数量
temp_size=LoadData in_file ":" 0
append Vert_UV_Size temp_size
--uv的数据
for i=1 to temp_size do
(
append Vert_UV (readValue in_file)
)
--uv face的 数量
temp_size==LoadData in_file ":" 0
append Face_UV_Size temp_size
for i=1 to temp_size do
(
append Face_uv (readValue in_file)
)
)
)
close in_file
)
meditmaterials[1].ambient=_Material_Ambient
meditmaterials[1].diffuse=_Material_Diffuse
meditmaterials[1].shaderbyname=_Material_type
meditmaterials[1].specular=_material_specular
meditmaterials[1].specularlevel=_material_specular_lv
meditmaterials[1].glossiness=_material_glossiness
meditmaterials[1].selfillumcolor=_Material_SelfillumColor
meditmaterials[1].selfillumamount=_Material_SelfillumAmount
meditmaterials[1].diffuseMapEnable=true
bmp =bitmaptexture filename: _Material_DiffTexPath
meditmaterials[1].diffusemap=bmp
new_mesh = mesh vertices:vert_array faces:face_array --materialIDs:#(0,1) tverts:vert_uv
for f = 1 to num_face do
(
setFaceSmoothGroup new_mesh f sgroup_array[f]
setFaceMatID new_mesh f matid_array[f]
setEdgeVis new_mesh f 1 edge_array[f][1]
setEdgeVis new_mesh f 2 edge_array[f][2]
setEdgeVis new_mesh f 3 edge_array[f][3]
)
myTransform = new_mesh.transform
new_mesh.transform.row1 = tm_row1[1]
new_mesh.transform.row2 = tm_row2[1]
new_mesh.transform.row3 = tm_row3[1]
new_mesh.transform.row4 = tm_row4[1]
new_mesh.name=(nodename as string)
new_mesh.material=meditmaterials[1]
meshop.setMapSupport new_mesh 0 true
meshop.setMapSupport new_mesh 1 true
--set vertex uv for every vertex
meshop.setNumMapVerts new_mesh 1 Vert_UV_Size[1] keep:false
for i=1 to Vert_UV_Size[1] do
(
meshop.setMapVert new_mesh 1 i Vert_UV[i]
)
--set face uv for every face
meshop.setnummapfaces new_mesh 1 Face_UV_Size[1] keep:false
for i=1 to Face_UV_Size[1] do
(
meshop.setMapFace new_mesh 1 i Face_UV[i]
)
update new_mesh
)
以下是导出插件:
到处插件很容易写,导入插件花了2倍于导出的时间
-- export by sssa2000
macroScript ExportGeo category:"HowTo2"
(
fn GetGeometry o =
(
Superclassof o == Geometryclass and classof o != TargetObject
)
fn DumpMaterial m file=
(
--只对Standard类型的材质处理
--获得diffuse and diffuse map
ismat=iskindof m material
if ismat then
(
name=m.name
format "Material Name-> %\n" name to: file
class_of_mat=classof m
--messagebox class_of_mat
if (class_of_mat )==Standardmaterial then
(
type=m.shaderByName
format "Material Type->%\n" type to: file
_ambient=m.ambient
format "Ambient Value->%\n" _ambient to:file
diffuse_value=m.diffuse
format "Diffuse Value->%\n" diffuse_value to:file
_specular=m.specular
format "Specular Value->%\n" _specular to:file
_specularLevel =m.specularLevel
format "SpecularLevel Value->%\n" _specularLevel to:file
_Glossiness=m.Glossiness
format "Glossiness Value->%\n" _Glossiness to:file
_selfIllumColor =m.selfIllumColor
format "SelfIllumColor Value->%\n" _selfIllumColor to:file
_selfIllumAmount =m.selfIllumAmount
format "SelfIllumAmount Value->%\n" _selfIllumAmount to:file
diffuse_map_path=m.diffusemap.filename
format "Diffuse Map Path->%\n" diffuse_map_path to:file
)
)
format "\n" to: file
)
--/////////////////////////////////////////////////////////////////////////////////////////
obj = pickobject filter:GetGeometry
if isValidNode obj then
(
nodename=obj.name
--First export the matrix
row1=obj.transform.row1
row2=obj.transform.row2
row3=obj.transform.row3
row4=obj.transform.row4
tmesh = snapshotAsMesh obj
out_name = GetSaveFileName()
if out_name != undefined then
(
out_file = createfile out_name
format "Node Name: %\n" nodename to: out_file
format "\n" to: out_file
--******************************************************
-- material info
node_material=obj.material
num_sub_material=getNumSubMtls obj.material
DumpMaterial obj.material out_file
for y=1 to num_sub_material do
(
sub_mat=getSubMtl obj.material y
DumpMaterial sub_mat= out_file
)
--******************************************************
format "Node TM Row1: %\n" row1 to: out_file
format "Node TM Row2: %\n" row2 to: out_file
format "Node TM Row3: %\n" row3 to: out_file
format "Node TM Row4: %\n" row4 to: out_file
--******************************************************
-- vertex info
num_verts = tmesh.numverts
num_faces = tmesh.numfaces
format "Number of Ver: %\n" num_verts to:out_file
for v = 1 to num_verts do
format "Ver%: %\n" v (getVert tmesh v) to:out_file
format "\n" to:out_file
--***********************************************
--face info
format "Number of Face: %\n" num_faces to:out_file
for f = 1 to num_faces do
(
face = getFace tmesh f
sgroup = getFaceSmoothGroup tmesh f
matid = getFaceMatId tmesh f
edge1 = getEdgeVis tmesh f 1
edge2 = getEdgeVis tmesh f 2
edge3 = getEdgeVis tmesh f 3
format "%,%,%,%,%,%\n" face sgroup matid edge1 edge2 edge3 to:out_file
)
--******************************************************
--uv info
channel=meshop.getnummaps tmesh --number of texture
format "\n" to: out_file
format "Channel Number:%\n" channel to:out_file
for i=1 to (channel-1) do
(
-- channel的计数从0开始
--channel 0 is vertex color so do not export it
IsSupport=meshop.getMapSupport tmesh i
if IsSupport==true then
(
format "Channel ID:%\n" i to:out_file
if classof obj.material.maps[i+1]==Bitmaptexture then
format "Map File Path->%\n" obj.material.maps[i+1].filename to: out_file
else
format "Map File Path->Null\n" to: out_file
num_uv_ver=meshop.getNumMapVerts tmesh i
num_uv_face=meshop.getNumMapFaces tmesh i
format "UVW Vertex Number:%\n" num_uv_ver to:out_file
for j=1 to num_uv_ver do
(
vert_uvw=meshop.getMapVert tmesh i j
--messagebox (vert_uvw as string)
format "% \n" vert_uvw to: out_file
)
format "UVW Face Number:%\n" num_uv_face to:out_file
for o=1 to num_uv_face do
(
uvw_face=meshop.getMapFace tmesh i o
format "% \n" uvw_face to: out_file
)
)
else
(
--format "Do Not Support Channel %\n" i to:out_file
)
)
close out_file
edit out_name
)
)
)