MAXScriptを一つにまとめて、UVも読めるようにした
中間ファイルのフォーマット
頂点数
[X,Y,Z]
・・・
テクスチャ頂点数
[U,V,W]
・・・
三角面数
[v1,v2,v3(頂点のインデックス)],[tv1,tv2,tv3(テクスチャ頂点のインデックス)],マテリアルID,エッジ1,エッジ2,エッジ3
ボーン数
ボーン名,親,長さ,[X,Y,Z],[先端の座標],[アップベクタ]
・・・
ボーンウェイト(ボーン数x頂点数個)
・・・
MAXScript
macroScript ImportMesh category:"HowTo"
(
vert_array = #()
face_array = #()
tv_array = #()
tf_array = #()
matid_array = #()
edge_array = #()
bone_array = #()
in_name = getOpenFileName()
if in_name != undefined then
(
in_file = openFile in_name
if in_file != undefined then
(
num_verts = readValue in_file
for v = 1 to num_verts do
(
append vert_array (readValue in_file)
)
num_tv = readValue in_file
for v=1 to num_tv do
(
append tv_array (readValue in_file)
)
num_faces = readValue in_file
for f = 1 to num_faces do
(
append face_array (readValue in_file)
append tf_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)
)
new_mesh = mesh vertices:vert_array faces:face_array materialIDs:matid_array tverts:tv_array
buildTVFaces new_mesh
for f=1 to num_faces do
(
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]
setTVFace new_mesh f tf_array[f]
)
update new_mesh
max modify mode
select new_mesh
addModifier new_mesh (Skin())
skin_mod = new_mesh.modifiers[1]
num_bones = readValue in_file
for b = 1 to num_bones do
(
bone_name = readDelimitedString in_file ","
bone_parent = readValue in_file
bone_length = readValue in_file
bone_pos = readValue in_file
bone_tip = readValue in_file
bone_upvec = readValue in_file
bone = BoneSys.createBone bone_pos bone_tip bone_upvec
append bone_array bone
bone.name = bone_name
bone.width = bone_length * 0.2
bone.height = bone_length * 0.2
bone.setBoneEnable true 0
if 0 < bone_parent then
bone.parent = bone_array[bone_parent]
skinops.addbone skin_mod bone 1
)
max modify mode
select new_mesh
skin_mod = new_mesh.modifiers[1]
if num_bones == skinops.getNumberBones skin_mod then
(
for b = 1 to num_bones do
(
for v = 1 to num_verts do
(
weight = readValue in_file
skinOps.setVertexWeights skin_mod v b weight
)--v
)--b
)--num_bone
close in_file
)--OpenFile
)--GetFileName
)--
LayoutGeneric.cpp
#include "main.h"
#include "LW_CMatrix.h"#include <vector>
#include <string>typedef std::vector<LWPntID> PointIDList;
typedef std::vector<LWPolID> PolygonIDList;
typedef std::string String;
typedef std::vector<String> StringList;
typedef std::vector<float> FList;
typedef struct{
String name;
LWFVector pos, tip, upvec;
int parentIndex, selfIndex;
FList weights;
LWItemID id;
float length;
}BoneData;
typedef std::vector<BoneData> BoneList;
static LWPanControlDesc desc; // required by macros in lwpanel.h
static LWValue ival={LWT_INTEGER};
static LWValue ivecval={LWT_VINT}; // required by macros in lwpanel.h
static LWValue fval={LWT_FLOAT};
static LWValue fvecval={LWT_VFLOAT};
static LWValue sval={LWT_STRING};
int getPntIDFunc(void *scanData, LWPntID pnt);
int getPolyIDFunc(void *scanData, LWPolID pol);
bool getFilename(GlobalFunc *global, char *filename, int maxlen);
DWORD getVIndex(const PointIDList *points, const LWPntID pnt);
int getSurfIndex(const StringList *NameList, const char *name, int numName);
void getBone(const LWItemInfo *iteminfo, const LWBoneInfo *boninfo, LWItemID bone, BoneList *bonlist, int parentIndex);
const char * getUVName(GlobalFunc *global, String &name);//----------------------------------------------------------------------------------------------------
// ハンドラーアクティベーション関数
//----------------------------------------------------------------------------------------------------
XCALL_(int) Activate(long version, GlobalFunc *global, LWLayoutGeneric *local, void *serverData)
{
if( LWLAYOUTGENERIC_VERSION != version )
return AFUNC_BADVERSION;LWInterfaceInfo *intinfo = (LWInterfaceInfo*)global( LWINTERFACEINFO_GLOBAL, GFUSE_TRANSIENT );
LWItemInfo *iteminfo = (LWItemInfo*)global( LWITEMINFO_GLOBAL, GFUSE_TRANSIENT );
LWMessageFuncs *msgf = (LWMessageFuncs*)global( LWMESSAGEFUNCS_GLOBAL, GFUSE_TRANSIENT );
LWObjectInfo *objinfo = (LWObjectInfo*)global( LWOBJECTINFO_GLOBAL, GFUSE_TRANSIENT );
LWSurfaceFuncs *surff = (LWSurfaceFuncs*)global( LWSURFACEFUNCS_GLOBAL, GFUSE_TRANSIENT );
LWBoneInfo *boninfo = (LWBoneInfo*)global( LWBONEINFO_GLOBAL, GFUSE_TRANSIENT );
const char *error;if( !intinfo || !iteminfo || !msgf || !objinfo || !surff || !boninfo )
return AFUNC_BADGLOBAL;LWItemID obj = *(intinfo->selItems);
if( LWI_OBJECT != iteminfo->type(obj) ){
msgf->error("", "");
return AFUNC_OK;
}LWMeshInfoID meshinfo = objinfo->meshInfo(obj, 0);
if( !meshinfo ){
msgf->error("", "");
return AFUNC_OK;
}String UVName;
error = getUVName(global, UVName);
if( error ){
msgf->error(error, "");
}//ポイント
DWORD numPnts = meshinfo->numPoints(meshinfo);
PointIDList pnts;
meshinfo->scanPoints(meshinfo, getPntIDFunc, &pnts);//ポリゴン
DWORD numPolys = meshinfo->numPolygons(meshinfo);
PolygonIDList pols;
meshinfo->scanPolys(meshinfo, getPolyIDFunc, &pols);
void *vmap = meshinfo->pntVLookup(meshinfo, LWVMAP_TXUV, UVName.c_str());
if( !vmap ){
msgf->error("", "");
return AFUNC_OK;
}
meshinfo->pntVSelect(meshinfo, vmap);
FList uv;
for(DWORD numTriPolys=0, dw=0; dw<numPolys; dw++){
int nVert = meshinfo->polSize(meshinfo, pols[dw]);
LWFVector fvec = { 0.0, 0.0, 0.0 };
if( 3 == nVert ){
numTriPolys++;
for(int i=0; i<nVert; i++){
if( meshinfo->pntVPGet(meshinfo, meshinfo->polVertex(meshinfo, pols[dw], i), pols[dw], fvec) ){
uv.push_back(fvec[0]);
uv.push_back(fvec[1]);
}
}
}else if( 3 < nVert ){
numTriPolys += (nVert - 2);
for(int i=0; i<nVert; i++){
if( meshinfo->pntVPGet(meshinfo, meshinfo->polVertex(meshinfo, pols[dw], i), pols[dw], fvec) ){
uv.push_back(fvec[0]);
uv.push_back(fvec[1]);
}
}
}
}//サーフェイス
LWSurfaceID *surfID = surff->byObject(objinfo->filename(obj));
int numSurf;
for( numSurf=0; surfID[numSurf]; numSurf++) ;
StringList surfNameList;
String tempString;
for(int i=0; i<numSurf; i++){
tempString = surff->name(surfID[i]);
surfNameList.push_back(tempString);
}//ボーン
BoneList bones;
for(LWItemID child=iteminfo->firstChild(obj); LWITEM_NULL != child; child=iteminfo->nextChild(obj, child)){
if( LWI_BONE == iteminfo->type(child) ) getBone(iteminfo, boninfo, child, &bones, -1);
}
DWORD numBones = bones.size();
for(dw=0; dw<numBones; dw++){
const char *weightName = boninfo->weightMap(bones[dw].id);
float tempF;
if( weightName ){
vmap = meshinfo->pntVLookup(meshinfo, LWVMAP_WGHT, weightName);
if( vmap ){
meshinfo->pntVSelect(meshinfo, vmap);
for(int i=0; i<numPnts; i++){
if( !meshinfo->pntVGet(meshinfo, pnts[i], &tempF) ){
tempF = 0.0;
}
bones[dw].weights.push_back(tempF);
}
}else{
for(i=0; i<numPnts; i++){
bones[dw].weights.push_back(0.0);
}
}
}else{
for(int i=0; i<numPnts; i++){
bones[dw].weights.push_back(0.0);
}
}
}//ファイルに出力
char filename[MAX_PATH];
if( !getFilename(global, filename, MAX_PATH) ){
msgf->error("", "");
return AFUNC_OK;
}FILE *fp = fopen(filename, "wt");
if( !fp ){
msgf->error("", "");
return AFUNC_OK;
}LWFVector pos;
fprintf(fp, "%d\n", numPnts);
for(dw=0; dw<numPnts; dw++){
meshinfo->pntBasePos(meshinfo, pnts[dw], pos);
fprintf(fp, "[%f,%f,%f]\n", pos[0]*39.37, pos[2]*39.37, pos[1]*39.37);
}DWORD numUVPnts = uv.size()*0.5;
fprintf(fp, "%d\n", numPnts+numUVPnts );
vmap = meshinfo->pntVLookup(meshinfo, LWVMAP_TXUV, UVName.c_str());
meshinfo->pntVSelect(meshinfo, vmap);
for(dw=0; dw<numPnts ; dw++){
LWFVector fvec;
if( meshinfo->pntVGet(meshinfo, pnts[dw], fvec) ){
fprintf(fp, "[%f,%f,0.0]\n", fvec[0], fvec[1]);
}else{
fprintf(fp, "[0.0,0.0,0.0]\n");
}
}
for(dw=0 ;dw<(numUVPnts*2); dw+=2){
fprintf(fp, "[%f,%f,0.0]\n", uv[dw], uv[dw+1]);
}int vIndex[3];
int uvwIndex[3];
DWORD uvwCurrent = numPnts + 1;
int matIndex;
const char *edgeIndex[3];
fprintf(fp, "%d\n", numTriPolys);
for(dw=0; dw<numPolys; dw++){
LWFVector fvec;
int nVert = meshinfo->polSize(meshinfo, pols[dw]);
matIndex = getSurfIndex(&surfNameList, meshinfo->polTag(meshinfo, pols[dw], LWPTAG_SURF), numSurf);
if( 3 == nVert ){
vIndex[0] = getVIndex(&pnts, meshinfo->polVertex(meshinfo, pols[dw], 2)) +1;
vIndex[1] = getVIndex(&pnts, meshinfo->polVertex(meshinfo, pols[dw], 1)) +1;
vIndex[2] = getVIndex(&pnts, meshinfo->polVertex(meshinfo, pols[dw], 0)) +1;
if( meshinfo->pntVPGet(meshinfo, meshinfo->polVertex(meshinfo, pols[dw], 2), pols[dw], fvec) ) uvwIndex[0] = uvwCurrent++; else uvwIndex[0] = vIndex[0];
if( meshinfo->pntVPGet(meshinfo, meshinfo->polVertex(meshinfo, pols[dw], 1), pols[dw], fvec) ) uvwIndex[1] = uvwCurrent++; else uvwIndex[1] = vIndex[1];
if( meshinfo->pntVPGet(meshinfo, meshinfo->polVertex(meshinfo, pols[dw], 0), pols[dw], fvec) ) uvwIndex[2] = uvwCurrent++; else uvwIndex[2] = vIndex[2];
edgeIndex[0] = "true"; edgeIndex[1] = "true"; edgeIndex[2] = "true";
fprintf(fp, "[%d,%d,%d],[%d,%d,%d],%d,%s,%s,%s\n", vIndex[0], vIndex[1], vIndex[2], uvwIndex[0], uvwIndex[1], uvwIndex[2], matIndex, edgeIndex[0], edgeIndex[1], edgeIndex[2]);
}else if( 3 < nVert ){
vIndex[0] = getVIndex(&pnts, meshinfo->polVertex(meshinfo, pols[dw], nVert - 1)) +1;
vIndex[1] = getVIndex(&pnts, meshinfo->polVertex(meshinfo, pols[dw], nVert - 2)) +1;
vIndex[2] = getVIndex(&pnts, meshinfo->polVertex(meshinfo, pols[dw], nVert - 3)) +1;
if( meshinfo->pntVPGet(meshinfo, meshinfo->polVertex(meshinfo, pols[dw], nVert - 1), pols[dw], fvec) ) uvwIndex[0] = uvwCurrent++; else uvwIndex[0] = vIndex[0];
if( meshinfo->pntVPGet(meshinfo, meshinfo->polVertex(meshinfo, pols[dw], nVert - 2), pols[dw], fvec) ) uvwIndex[1] = uvwCurrent++; else uvwIndex[1] = vIndex[1];
if( meshinfo->pntVPGet(meshinfo, meshinfo->polVertex(meshinfo, pols[dw], nVert - 3), pols[dw], fvec) ) uvwIndex[2] = uvwCurrent++; else uvwIndex[2] = vIndex[2];
edgeIndex[0] = "true"; edgeIndex[1] = "true"; edgeIndex[2] = "false";
fprintf(fp, "[%d,%d,%d],[%d,%d,%d],%d,%s,%s,%s\n", vIndex[0], vIndex[1], vIndex[2], uvwIndex[0], uvwIndex[1], uvwIndex[2], matIndex, edgeIndex[0], edgeIndex[1], edgeIndex[2]);
edgeIndex[0] = "false";
for(int i=nVert-4; i>=0; i--){
vIndex[1] = vIndex[2];
uvwIndex[1] = uvwIndex[2];
vIndex[2] = getVIndex(&pnts, meshinfo->polVertex(meshinfo, pols[dw], i)) +1;
if( meshinfo->pntVPGet(meshinfo, meshinfo->polVertex(meshinfo, pols[dw], i), pols[dw], fvec) ) uvwIndex[2] = uvwCurrent++; else uvwIndex[2] = vIndex[2];
if( 0 == i ) edgeIndex[2] = "true";
fprintf(fp, "[%d,%d,%d],[%d,%d,%d],%d,%s,%s,%s\n", vIndex[0], vIndex[1], vIndex[2], uvwIndex[0], uvwIndex[1], uvwIndex[2], matIndex, edgeIndex[0], edgeIndex[1], edgeIndex[2]);
}
}
}fprintf(fp, "%d\n", numBones);
for(dw=0; dw<numBones; dw++){
fprintf(fp, "%s,", bones[dw].name.c_str());
fprintf(fp, "%d,", bones[dw].parentIndex + 1);
fprintf(fp, "%f,", bones[dw].length*39.37);
fprintf(fp, "[%f,%f,%f],", bones[dw].pos[0]*39.37, bones[dw].pos[2]*39.37, bones[dw].pos[1]*39.37);
fprintf(fp, "[%f,%f,%f],", bones[dw].tip[0]*39.37, bones[dw].tip[2]*39.37, bones[dw].tip[1]*39.37);
fprintf(fp, "[%f,%f,%f]\n", bones[dw].upvec[0]*39.37, bones[dw].upvec[2]*39.37, bones[dw].upvec[1]*39.37);
}for(dw=0; dw<numBones; dw++){
for(DWORD i=0; i<numPnts; i++){
fprintf(fp, "%f\n", bones[dw].weights[i]);
}
}return AFUNC_OK;
}
int getPntIDFunc(void *scanData, LWPntID pnt)
{
PointIDList *p = (PointIDList*)scanData;
p->push_back(pnt);
return 0;
}
int getPolyIDFunc(void *scanData, LWPolID pol)
{
PolygonIDList *p = (PolygonIDList*)scanData;
p->push_back(pol);
return 0;
}
bool getFilename(GlobalFunc *global, char *filename, int maxlen)
{
LWFileReqFunc *filereq = (LWFileReqFunc*)global( LWFILEREQFUNC_GLOBAL, GFUSE_TRANSIENT );
if( !filereq ) return false;static char node[MAX_PATH] = "*.txt";
static char path[MAX_PATH] = "";int result = filereq("Save", node, path, filename, maxlen);
if( result ) return true;
else return false;
}
DWORD getVIndex(const PointIDList *points, const LWPntID pnt)
{
for(DWORD dw=0; (*points)[dw] != pnt; dw++) ;return dw;
}
int getSurfIndex(const StringList *NameList, const char *name, int numName)
{
for(int i=0; i<numName; i++){
if( 0 == strcmp((*NameList)[i].c_str(), name) ) return i+1;
}
return 0;
}LW_CMatrix_4x4 getMatrix(LW_CMatrix_4x4 matrix, const LWItemInfo *iteminfo, const LWBoneInfo *boninfo, LWItemID id)
{
LW_CMatrix_4x4 temp;
if( LWITEM_NULL == id || LWI_BONE != iteminfo->type(id) ) return matrix;LWDVector dvec;
boninfo->restParam(id, LWIP_ROTATION, dvec);
temp.rotateHPB(dvec[0], dvec[1], dvec[2]);
boninfo->restParam(id, LWIP_POSITION, dvec);
temp.translate(dvec[0], dvec[1], dvec[2]);return getMatrix(matrix * temp, iteminfo, boninfo, iteminfo->parent(id));
}void getBone(const LWItemInfo *iteminfo, const LWBoneInfo *boninfo, LWItemID bone, BoneList *bonlist, int parentIndex)
{
BoneData bondata;
bondata.id = bone;
bondata.name = iteminfo->name(bone);
bondata.parentIndex = parentIndex;
bondata.selfIndex = bonlist->size();
bondata.length = boninfo->restLength(bone);
bondata.pos[0] = 0.0; bondata.pos[1] = 0.0; bondata.pos[2] = 0.0;
bondata.tip[0] = 0.0; bondata.tip[1] = 0.0; bondata.tip[2] = bondata.length;
bondata.upvec[0] = 0.0; bondata.upvec[1] = 1.0; bondata.upvec[2] = 0.0;
LW_CMatrix_4x4 matrix;
matrix.init();
matrix = getMatrix(matrix, iteminfo, boninfo, bone);
matrix.Transform(bondata.pos);
matrix.Transform(bondata.tip);
matrix.Transform(bondata.upvec);bonlist->push_back(bondata);
for(LWItemID child=iteminfo->firstChild(bone); LWITEM_NULL != child; child=iteminfo->nextChild(bone, child)){
if( LWI_BONE == iteminfo->type(child) ) getBone(iteminfo, boninfo, child, bonlist, bondata.selfIndex);
}
}
const char * getUVName(GlobalFunc *global, String &name)
{
LWObjectFuncs *objfunc = (LWObjectFuncs*)global( LWOBJECTFUNCS_GLOBAL, GFUSE_TRANSIENT );
LWPanelFuncs *panel = (LWPanelFuncs*)global(LWPANELFUNCS_GLOBAL, GFUSE_TRANSIENT);
LWPanelID pid = NULL;
LWControl *ctl;if( !objfunc || !panel ) return false;
int numMaps = objfunc->numVMaps(LWVMAP_TXUV);
if( 0 == numMaps ){
return "There is not UVMaps.";
}else if( 1 == numMaps ){
name = objfunc->vmapName(LWVMAP_TXUV, 0);
return NULL;
}
const char **items = new const char*[numMaps+1];
for(int i=0; i<numMaps; i++){
items[i] = objfunc->vmapName(LWVMAP_TXUV, i);
}
items[numMaps] = NULL;if( pid = PAN_CREATE(panel, SERVERNAME) ){
ctl = POPUP_CTL(panel, pid, "Select UVMap", items);
if( PAN_POST(panel, pid) ){
GET_INT(ctl, i);
name = items[i];
}else{
return "Canceled";
}
PAN_KILL(panel, pid);
}
return NULL;
}