LWで作ったモデルデータをMAXに持っていきたくて、いろいろ試行錯誤してみた
FBXファイルでほぼ完璧にデータを持っていけるんだけど、たまにうまくいかない場合がある(どうしても持っていきたいデータがうまくいかない)のでプラグインを作ってみようと思った
.maxファイルのフォーマットは公開されていないので、LWのエクスポーターを作るのは無理そうなので、MAXScriptでlwoインポーターを作ったんだけどバイナリファイルの実数がMAXScriptでうまく読み込め無いので断念
結局、間にテキストファイルを通して何とかMAXに持っていくことにした
今のところメッシュとボーンとボーンウェイトだけ
MAXScript
チュートリアルを拡張して、ボーンも読み込むようにした
macroScript ImportMesh category:"HowTo"
(
vert_array = #()
face_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_faces = readValue in_file
for f = 1 to num_faces do
(
append face_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
for f=1 to num_faces do
(
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]
)
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
)
close in_file
)--OpenFile
)--GetFileName
)--
ウエイトマップの読み込み
macroScript LoadWeight category:"HowTo"
(
in_name = getOpenFileName()
if in_name != undefined then
(
in_file = openFile in_name
if in_file != undefined then
(
num_bones = readValue in_file
num_verts = readValue in_file
obj = selection[1]
skin_mod = obj.modifiers[1]
if num_bones == skinops.getNumberBones skin_mod then
(
if num_verts == obj.numverts 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_verts
)--num_bone
)--OpenFile
close in_file
)--GetFileName
)
LW LayoutGenericプラグイン
LayoutGeneric.cpp
#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;
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);
//----------------------------------------------------------------------------------------------------
// ハンドラーアクティベーション関数
//----------------------------------------------------------------------------------------------------
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 );
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;
}
//ポイント
DWORD numPnts = meshinfo->numPoints(meshinfo);
PointIDList pnts;
meshinfo->scanPoints(meshinfo, getPntIDFunc, &pnts);
//ポリゴン
DWORD numPolys = meshinfo->numPolygons(meshinfo);
PolygonIDList pols;
meshinfo->scanPolys(meshinfo, getPolyIDFunc, &pols);
for(DWORD numTriPolys=0, dw=0; dw<numPolys; dw++){
int nVert = meshinfo->polSize(meshinfo, pols[dw]);
if( 3 == nVert ){
numTriPolys++;
}else if( 3 < nVert ){
numTriPolys += (nVert - 2);
}
}
//サーフェイス
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);
void *vmap;
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;
}
//fprintf(fp, "%s\n", SERVERNAME);
LWFVector pos;
//fprintf(fp, "Points : %d\n", numPnts);
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);
}
int vIndex[3];
int matIndex;
const char *edgeIndex[3];
//fprintf(fp, "Faces : %d\n", numTriPolys);
fprintf(fp, "%d\n", numTriPolys);
for(dw=0; dw<numPolys; dw++){
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;
edgeIndex[0] = "true"; edgeIndex[1] = "true"; edgeIndex[2] = "true";
fprintf(fp, "[%d,%d,%d],%d,%s,%s,%s\n", vIndex[0], vIndex[1], vIndex[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;
edgeIndex[0] = "true"; edgeIndex[1] = "true"; edgeIndex[2] = "false";
fprintf(fp, "[%d,%d,%d],%d,%s,%s,%s\n", vIndex[0], vIndex[1], vIndex[2], matIndex, edgeIndex[0], edgeIndex[1], edgeIndex[2]);
edgeIndex[0] = "false";
for(int i=nVert-4; i>=0; i--){
vIndex[1] = vIndex[2];
vIndex[2] = getVIndex(&pnts, meshinfo->polVertex(meshinfo, pols[dw], i)) +1;
if( 0 == i ) edgeIndex[2] = "true";
fprintf(fp, "[%d,%d,%d],%d,%s,%s,%s\n", vIndex[0], vIndex[1], vIndex[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);
}
fclose(fp);
strcat(filename, ".weight");
fp = fopen(filename, "wt");
fprintf(fp, "%d,%d\n", numBones, numPnts);
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);
}
}
LW_CMatrix.h
#ifndef __LW_CMATRIX_H__
#define __LW_CMATRIX_H__
#include <math.h>
#include <lwtypes.h>
class LW_CMatrix_4x4 {
protected:
double m_matrix[4][4];
public:
LW_CMatrix_4x4();
~LW_CMatrix_4x4();
public:
void init();
void translate(double x, double y, double z);
void rotateX(double x);
void rotateY(double y);
void rotateZ(double z);
void rotateHPB(double h, double p, double b);
void scale(double x, double y, double z);
void Transform(LWDVector pos);
void Transform(LWFVector pos);
LW_CMatrix_4x4 operator*(const LW_CMatrix_4x4 &mat44);
LW_CMatrix_4x4 &operator=(const LW_CMatrix_4x4 &mat44);
};
LW_CMatrix.cpp
#include "LW_CMatrix.h"
LW_CMatrix_4x4::LW_CMatrix_4x4()
{
m_matrix[0][0] = 1.0; m_matrix[0][1] = 0.0; m_matrix[0][2] = 0.0; m_matrix[0][3] = 0.0;
m_matrix[1][0] = 0.0; m_matrix[1][1] = 1.0; m_matrix[1][2] = 0.0; m_matrix[1][3] = 0.0;
m_matrix[2][0] = 0.0; m_matrix[2][1] = 0.0; m_matrix[2][2] = 1.0; m_matrix[2][3] = 0.0;
m_matrix[3][0] = 0.0; m_matrix[3][1] = 0.0; m_matrix[3][2] = 0.0; m_matrix[3][3] = 1.0;
}
LW_CMatrix_4x4::~LW_CMatrix_4x4()
{
}
void LW_CMatrix_4x4::init()
{
m_matrix[0][0] = 1.0; m_matrix[0][1] = 0.0; m_matrix[0][2] = 0.0; m_matrix[0][3] = 0.0;
m_matrix[1][0] = 0.0; m_matrix[1][1] = 1.0; m_matrix[1][2] = 0.0; m_matrix[1][3] = 0.0;
m_matrix[2][0] = 0.0; m_matrix[2][1] = 0.0; m_matrix[2][2] = 1.0; m_matrix[2][3] = 0.0;
m_matrix[3][0] = 0.0; m_matrix[3][1] = 0.0; m_matrix[3][2] = 0.0; m_matrix[3][3] = 1.0;
}
void LW_CMatrix_4x4::translate(double x, double y, double z)
{
m_matrix[0][0] = m_matrix[0][0] + m_matrix[0][3] * x;
m_matrix[0][1] = m_matrix[0][1] + m_matrix[0][3] * y;
m_matrix[0][2] = m_matrix[0][2] + m_matrix[0][3] * z;
m_matrix[1][0] = m_matrix[1][0] + m_matrix[1][3] * x;
m_matrix[1][1] = m_matrix[1][1] + m_matrix[1][3] * y;
m_matrix[1][2] = m_matrix[1][2] + m_matrix[1][3] * z;
m_matrix[2][0] = m_matrix[2][0] + m_matrix[2][3] * x;
m_matrix[2][1] = m_matrix[2][1] + m_matrix[2][3] * y;
m_matrix[2][2] = m_matrix[2][2] + m_matrix[2][3] * z;
m_matrix[3][0] = m_matrix[3][0] + m_matrix[3][3] * x;
m_matrix[3][1] = m_matrix[3][1] + m_matrix[3][3] * y;
m_matrix[3][2] = m_matrix[3][2] + m_matrix[3][3] * z;
}
void LW_CMatrix_4x4::rotateX(double x)
{
double s = sin(x);
double c = cos(x);
double m[4][4];
int i, j;
for(i=0; i<4; i++){
for(j=0; j<4; j++){
m[i][j] = m_matrix[i][j];
}
}
m_matrix[0][1] = m[0][1]*c - m[0][2]*s;
m_matrix[0][2] = m[0][1]*s + m[0][2]*c;
m_matrix[1][1] = m[1][1]*c - m[1][2]*s;
m_matrix[1][2] = m[1][1]*s + m[1][2]*c;
m_matrix[2][1] = m[2][1]*c - m[2][2]*s;
m_matrix[2][2] = m[2][1]*s + m[2][2]*c;
m_matrix[3][1] = m[3][1]*c - m[3][2]*s;
m_matrix[3][2] = m[3][1]*s + m[3][2]*c;
}
void LW_CMatrix_4x4::rotateY(double y)
{
double s = sin(y);
double c = cos(y);
double m[4][4];
int i, j;
for(i=0; i<4; i++){
for(j=0; j<4; j++){
m[i][j] = m_matrix[i][j];
}
}
m_matrix[0][0] = m[0][0]*c + m[0][2]*s;
m_matrix[0][2] = -m[0][0]*s + m[0][2]*c;
m_matrix[1][0] = m[1][0]*c + m[1][2]*s;
m_matrix[1][2] = -m[1][0]*s + m[1][2]*c;
m_matrix[2][0] = m[2][0]*c + m[2][2]*s;
m_matrix[2][2] = -m[2][0]*s + m[2][2]*c;
m_matrix[3][0] = m[3][0]*c + m[3][2]*s;
m_matrix[3][2] = -m[3][0]*s + m[3][2]*c;
}
void LW_CMatrix_4x4::rotateZ(double z)
{
double s = sin(z);
double c = cos(z);
double m[4][4];
int i, j;
for(i=0; i<4; i++){
for(j=0; j<4; j++){
m[i][j] = m_matrix[i][j];
}
}
m_matrix[0][0] = m[0][0]*c - m[0][1]*s;
m_matrix[0][1] = m[0][0]*s + m[0][1]*c;
m_matrix[1][0] = m[1][0]*c - m[1][1]*s;
m_matrix[1][1] = m[1][0]*s + m[1][1]*c;
m_matrix[2][0] = m[2][0]*c - m[2][1]*s;
m_matrix[2][1] = m[2][0]*s + m[2][1]*c;
m_matrix[3][0] = m[3][0]*c - m[3][1]*s;
m_matrix[3][1] = m[3][0]*s + m[3][1]*c;
}
void LW_CMatrix_4x4::rotateHPB(double h, double p, double b)
{
rotateZ(b);
rotateX(p);
rotateY(h);
}
void LW_CMatrix_4x4::scale(double x, double y, double z)
{
m_matrix[0][0] = m_matrix[0][0] * x;
m_matrix[0][1] = m_matrix[0][1] * y;
m_matrix[0][2] = m_matrix[0][2] * z;
m_matrix[1][0] = m_matrix[1][0] * x;
m_matrix[1][1] = m_matrix[1][1] * y;
m_matrix[1][2] = m_matrix[1][2] * z;
m_matrix[2][0] = m_matrix[2][0] * x;
m_matrix[2][1] = m_matrix[2][1] * y;
m_matrix[2][2] = m_matrix[2][2] * z;
m_matrix[3][0] = m_matrix[3][0] * x;
m_matrix[3][1] = m_matrix[3][1] * y;
m_matrix[3][2] = m_matrix[3][2] * z;
}
void LW_CMatrix_4x4::Transform(LWDVector pos)
{
LWDVector temp = { pos[0], pos[1], pos[2] };
pos[0] = temp[0]*m_matrix[0][0] + temp[1]*m_matrix[1][0] + temp[2]*m_matrix[2][0] + m_matrix[3][0];
pos[1] = temp[0]*m_matrix[0][1] + temp[1]*m_matrix[1][1] + temp[2]*m_matrix[2][1] + m_matrix[3][1];
pos[2] = temp[0]*m_matrix[0][2] + temp[1]*m_matrix[1][2] + temp[2]*m_matrix[2][2] + m_matrix[3][2];
}
void LW_CMatrix_4x4::Transform(LWFVector pos)
{
LWDVector dpos = { pos[0], pos[1], pos[2] };
int i;
Transform(dpos);
for(i=0; i<3; i++)
pos[i] = (float)dpos[i];
}
LW_CMatrix_4x4 LW_CMatrix_4x4::operator*(const LW_CMatrix_4x4 &mat44)
{
LW_CMatrix_4x4 mat;
for(int i=0; i<4; i++){
for(int j=0; j<4; j++){
mat.m_matrix[i][j] = m_matrix[i][0]*mat44.m_matrix[0][j] +
m_matrix[i][1]*mat44.m_matrix[1][j] +
m_matrix[i][2]*mat44.m_matrix[2][j] +
m_matrix[i][3]*mat44.m_matrix[3][j];
}
}
return mat;
}
LW_CMatrix_4x4 & LW_CMatrix_4x4::operator=(const LW_CMatrix_4x4 &mat44)
{
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
m_matrix[i][j] = mat44.m_matrix[i][j];
return *this;
}