![](http://static.blog.csdn.net/images/category_icon.jpg)
版权声明:本文为博主原创文章,未经博主允许不得转载。
Prepare:
1. 3D Studio MAX Plugin AppWizard can be found in the directory /3dsmax5/maxsdk/Help/SDKAPWZ
2. Copy SDKAPWZ.awx file into Visual Studio directory, e.g. C:/Program Files/Microsoft Visual Studio/Common/MSDev98/Bin/IDE
3. Run Visual C++ and click new. The appwizard will appear in the list of options.click "File Export", type exporter in the Plugin category, find the paths that you want to use and then the appwizard creates the skeleton code .
Plug-in Requirements:
int ExtCount() :
Returns the number of file extensions that the exporter provides (for our example, we provide 1)
const TCHAR Ext(int n) :
Returns the 3-letter file extension string for the given extension index (0-based).
const TCHAR LongDesc() :
Provides the long description of the file export format.
const TCHAR ShortDesc() :
Provides the short description of the file export format, shown in the file export dialog drop-down.
const TCHAR AuthorName() :
Provides the string that describes the author and/or company of the exporter plugin.
const TCHAR CopyrightMessage() :
Provides the string that shows the copyright for the given exporter and/or exporter format.
const TCHAR OtherMessage1() :
not used
const TCHAR OtherMessage2() :
not used
unsigned int Version() :
Somewhat redundant, but returns a version number for the exporter.
void ShowAbout() :
Shows an about box, accessible by the user from the main MAX export dialog.
int DoExport() :
The actual export method. BOOL SupportsOptions() :
Returns TRUE if the exporter supports some custom export options. Currently, only one option (export selected versus export entire scene) exists.
Export Functions:
//test if is a mesh node
BOOL IsMesh(INode* pNode)
{
if(pNode==NULL)
return FALSE;
if(!pNode->IsRootNode())
{
ObjectState obs=pNode->EvalWorldState(0);
if(obs.obj)
{
//GEOMOBJECT_CLASS_ID is include EDITTRIOBJ_CLASS_ID
//EDITTRIOBJ_CLASS_ID is EditMesh type id
//if(obs.obj->SuperClassID()==GEOMOBJECT_CLASS_ID)
if(obs.obj->ClassID()==Class_ID(EDITTRIOBJ_CLASS_ID,0))
return TRUE;
}
}
return FALSE;
}
//test if is a bone or biped controller
BOOL IsBone(INode* pNode)
{
if(pNode==NULL)
return FALSE;
ObjectState obs=pNode->EvalWorldState(0);
if(obs.obj==NULL)
return FALSE;
if(obs.obj->ClassID()==BONE_OBJ_CLASSID) //bone class id
return TRUE;
if(obs.obj->ClassID()==Class_ID(BONE_CLASS_ID, 0)) //include with Helper
return TRUE;
if(obs.obj->ClassID()==Class_ID(DUMMY_CLASS_ID, 0)) //include with Helper
return FALSE;
Control* ctrl=pNode->GetTMController();
if(ctrl->ClassID() == BIPSLAVE_CONTROL_CLASS_ID || //others biped parts
ctrl->ClassID() == BIPBODY_CONTROL_CLASS_ID //biped root
)
return TRUE;
return FALSE;
}
//Export mesh
BOOL ExportMesh(INode* pNode,FILE* out)
{
if((!pNode)||(!IsMesh(pNode)))
return FALSE;
Mesh_hdr meshHdr;
memset(&meshHdr,0,sizeof(Mesh_hdr));
Matrix3 tm=pNode->GetObjectTM(0);
ObjectState os=pNode->EvalWorldState(0);
if(os.obj)
{
Object *obj = os.obj;
if (obj && obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0)))
{
TriObject * tri = NULL;
tri = (TriObject *) obj->ConvertToType(0, Class_ID(TRIOBJ_CLASS_ID, 0));
if (tri) {
Mesh mesh = tri->GetMesh();
long startPos = ftell(out);
fseek(out, sizeof(Mesh_hdr), SEEK_CUR);
mesh.buildBoundingBox();
Box3 b=mesh.getBoundingBox();
......
meshHdr.vertCnt=mesh.getNumVerts();
meshHdr.vertOfS=ftell(out);
for(int i=0;i<meshHdr.vertCnt;i++)
{
Point3 pnt=mesh.getVert(i)*tm;
MAXtoGL(pnt);
fwrite(&pnt.x, sizeof(float), 3, out);
}
mesh.buildNormals();
meshHdr.normCnt=mesh.getNumVerts();
meshHdr.normOfS=ftell(out);
for(i=0;i<meshHdr.normCnt;i++)
{
Point3 norm=Normalize(mesh.getNormal(i));
MAXtoGL(norm);
fwrite(&norm.x,sizeof(float),3,out);
}
meshHdr.textureCnt=mesh.getNumTVerts();
Texture_hdr* tp=NULL;
//texture verts map to mesh verts
if(meshHdr.textureCnt>0)
{
meshHdr.textureCnt=meshHdr.vertCnt;
tp=new Texture_hdr[meshHdr.textureCnt];
memset(tp,0,sizeof(Texture_hdr)*meshHdr.textureCnt);
}
meshHdr.faceCnt=mesh.getNumFaces();
meshHdr.faceOfS=ftell(out);
for(i=0;i<meshHdr.faceCnt;i++)
{
Face_hdr fHdr;
memset(&fHdr,0,sizeof(Face_hdr));
fHdr.vert[0]=mesh.faces[i].v[0];
fHdr.vert[1]=mesh.faces[i].v[1];
fHdr.vert[2]=mesh.faces[i].v[2];
if(tp)
{
for(int j=0;j<3;j++)
if((tp[fHdr.vert[j]].u==0)&&(tp[fHdr.vert[j]].v==0))
{
tp[fHdr.vert[j]].u=mesh.tVerts[mesh.tvFace[i].getTVert(j)].x;
tp[fHdr.vert[j]].v=mesh.tVerts[mesh.tvFace[i].getTVert(j)].y;
}
}
fwrite(&fHdr,sizeof(Face_hdr),1,out);
}
meshHdr.textureOfS=ftell(out);
if(tp)
{
fwrite(tp,sizeof(Texture_hdr),meshHdr.textureCnt,out);
}
//all texture vert is follow:
/*
meshHdr.textureCnt=mesh.getNumTVerts();
meshHdr.textureOfS=ftell(out);
for(i=0;i<meshHdr.textureCnt;i++)
{
Texture_hdr tHdr;
memset(&tHdr,0,sizeof(Texture_hdr));
tHdr.u=mesh.tVerts[i].x;
tHdr.v=mesh.tVerts[i].y;
fwrite(&tHdr,sizeof(Texture_hdr),1,out);
}
*/
meshHdr.materialOfs=ftell(out);
Mtl* mtl=pNode->GetMtl();//just only one or zero
if(mtl)
{
if (mtl->ClassID() == Class_ID(DMTL_CLASS_ID, 0)) //standard material
{
StdMat* std = (StdMat *)mtl;
if(std)
{
Material_hdr mHdr;
Color tmpCl;
memset(&mHdr,0,sizeof(Material_hdr));
long mtlStart=ftell(out);
fseek(out,sizeof(Material_hdr),SEEK_CUR);
meshHdr.materialCnt=1;
tmpCl=std->GetAmbient(0);
.............
tmpCl=std->GetDiffuse(0);
.............
tmpCl=std->GetSpecular(0);
.............
mHdr.shininess=std->GetShininess(0);
mHdr.opacity=std->GetOpacity(0);
Texmap *tmap = std->GetSubTexmap(ID_DI);//diffuce channel
if(tmap)
{
if (tmap->ClassID() == Class_ID(BMTEX_CLASS_ID, 0))
{
BitmapTex *bmt = (BitmapTex*) tmap; //bitmap inform
...............
}
}
long mtlEnd=ftell(out);
fseek(out,mtlStart,SEEK_SET);
fwrite(&mHdr,sizeof(Material_hdr),1,out);
fseek(out,mtlEnd,SEEK_SET);
}
}
else if(mtl->ClassID() == Class_ID(MULTI_CLASS_ID,0))
{
Material_hdr pmHdr;
long pmtlStart=ftell(out);
fseek(out,sizeof(Material_hdr),SEEK_CUR);
pmHdr.subCnt=mtl->NumSubMtls();
pmHdr.subOfs=ftell(out);
for(int j=0;j<pmHdr.subCnt;j++)
{
Mtl* sMtl=mtl->GetSubMtl(j);
..........................
}
}
}
long endPos = ftell(out);
fseek(out, startPos, SEEK_SET);
fwrite(&meshHdr, sizeof(Mesh_hdr), 1, out);
fseek(out, endPos, SEEK_SET);
for(int n=0;n<pNode->NumberOfChildren();n++)
{
ExportMesh(pNode->GetChildNode(n),pCnt,out,fp);
}
}
}
}
return TRUE;
}
//other way to get mesh
// dummy view used internally by WriteMesh
class NullView : public View {
public:
Point2 ViewToScreen(Point3 p)
{
return Point2(p.x,p.y);
}
NullView() {
worldToView.IdentityMatrix();
screenW=800.0f; screenH = 600.0f;
}
};
static NullView nullView;
int needDelete;
Mesh &mesh=*(((GeomObject*)os.obj)->GetRenderMesh(0,pNode,nullView,needDelete));