2019独角兽企业重金招聘Python工程师标准>>>
目的是为OSG做自定义的导出插件. 记录取得数据的方法.
Max在代码中会提供一个INode对象. 从这个对象里取出各种数据. getSkin这个函数取出了ISkin修改器 下面这个函数一样是用于学习, 把数据输出到文本文件
`
ISkin* OSGExp::getSkin(INode *pINode)
{
// get the object reference of the node
Object *pObject;
pObject = pINode->GetObjectRef();
if (pObject == 0) return 0;
// loop through all derived objects
ObjectState _objectState = pINode->EvalWorldState(_ip->GetTime());// Arcadia 2018-09-10
if (_objectState.obj->SuperClassID() == GEOMOBJECT_CLASS_ID)// Arcadia 2018-09-10 有顶点数据,才会有蒙皮
{
IDerivedObject *pDerivedObject;
pDerivedObject = static_cast(pObject);
// loop through all modifiers 遍历所有的修改器
int stackId;
Modifier *pModifier;// 这里用于存放当前修改器, 用于试着转成蒙皮
ISkin* _skin = NULL;
for (stackId = 0; stackId < pDerivedObject->NumModifiers(); stackId++)
{
_skin = NULL;
// get the modifier
if (NULL == pDerivedObject->GetModifier(stackId))
{
continue;
}
// 蒙皮在Max中是个修改器, 取得这个修改器,再转成_skin
pModifier = pDerivedObject->GetModifier(stackId);
// Arcadia 2018-09-10
if (pModifier)
{
char _sTemp[255];
// 蒙皮数据的上下文:
_skin = dynamic_cast(pModifier);
if (_skin)
{
}// END if(_skin)
}
}
return _skin;
}
return 0;
}
`
函数readSkinData解析蒙皮数据 在Max导出插件制作过程中, 用写文件的方式调试比较方便 每个顶点对应几个有作用的骨骼, GetNumAssignedBones 取得有作用的骨骼 然后再遍历取得这个顶点的各个权重值. 并遍历取得相关骨骼的序号.
这里要注意的一点是, 所有骨骼是一个数组, 单个顶点的作用骨骼又是另一数组, 用单个顶点作用骨骼的下标可以取得骨骼于[所有骨骼数组]的下标.
` /** * 读取蒙皮数据, 输出到文件, 用于调试与学习 */ void OSGExp::readSkinData(ISkin skin,INode node) { using std::sprintf; string labelStart("\n S S S S S S S S S S S S\n"); m_FileObj.write(labelStart.c_str(), labelStart.size());
char _sTemp[255];
{
m_FileObj.write("有转成ISkin\n", string("有转成ISkin\n").size());
ISkinContextData *_data = skin->GetContextInterface(node);
sprintf(_sTemp, "点数:\t%d\n", _data->GetNumPoints());
m_FileObj.write(_sTemp, string(_sTemp).size());
sprintf(_sTemp, "骨骼数:\t%d\n", skin->GetNumBones());
m_FileObj.write(_sTemp, string(_sTemp).size());
Matrix3 _mt3;
sprintf(_sTemp, "SKIN_OK?\t%d\n",SKIN_OK == skin->GetSkinInitTM(node,_mt3) ); // 2018-09-12 返回是 SKIN_INVALID_NODE_PTR 不知会不会有问题 GetSkinInitTM是OK的, 但GetBoneInitTM不OK
m_FileObj.write(_sTemp, string(_sTemp).size());
// 取骨骼:
for (int i = 0; i < skin->GetNumBones(); ++i)
{
INode* nodeBone = skin->GetBone(i);
const wchar_t* wc_strName = nodeBone->GetName();
string s_strName = Util::TDuW2A(wc_strName);
sprintf(_sTemp, "骨骼名:\t%d\t%s", i, s_strName.c_str() );
m_FileObj.write(_sTemp, string(_sTemp).size());
switch ( skin->GetBoneProperty(i) )
{
case BONE_LOCK_FLAG:
sprintf(_sTemp, "\t%s", "BONE_LOCK_FLAG");
break;
case BONE_ABSOLUTE_FLAG:
sprintf(_sTemp, "\t%s", "BONE_ABSOLUTE_FLAG");
break;
case BONE_SPLINE_FLAG:
sprintf(_sTemp, "\t%s", "BONE_SPLINE_FLAG");
break;
case BONE_SPLINECLOSED_FLAG:
sprintf(_sTemp, "\t%s", "BONE_SPLINECLOSED_FLAG");
break;
case BONE_DRAW_ENVELOPE_FLAG:
sprintf(_sTemp, "\t%s", "BONE_DRAW_ENVELOPE_FLAG");
break;
case BONE_BONE_FLAG:
sprintf(_sTemp, "\t%s", "BONE_BONE_FLAG");
break;
case BONE_DEAD_FLAG:
sprintf(_sTemp, "\t%s", "BONE_DEAD_FLAG");
break;
}
m_FileObj.write(_sTemp, string(_sTemp).size());
// Bone TM:
union xxx {
xxx() {}
Matrix3 mt3_3;// = skin->GetBoneTm(i);
float m[4][3];// = (float*)mt3_3;
} _getDataU;
_getDataU.mt3_3 = skin->GetBoneTm(i);
sprintf(_sTemp, "\t坐标Z:\t%f", _getDataU.m[3][2]);
m_FileObj.write(_sTemp, string(_sTemp).size());
sprintf(_sTemp, "\n");
m_FileObj.write(_sTemp, string(_sTemp).size());
}
}// END if(_skin)
// GetNumBonesFlat:
sprintf(_sTemp, "GetNumBonesFlat:\t%d\n", skin->GetNumBonesFlat());
m_FileObj.write(_sTemp, string(_sTemp).size());
// GetRefFrame:
sprintf(_sTemp, "GetRefFrame:\t%d\n", skin->GetRefFrame());
m_FileObj.write(_sTemp, string(_sTemp).size());
// 输出各顶点坐标:
// ISkinContextData:
{
sprintf(_sTemp, "ISkinContextData:\n");
m_FileObj.write(_sTemp, string(_sTemp).size());
ISkinContextData *skinData = skin->GetContextInterface(node);
sprintf(_sTemp, "\tGetNumPoints:\t%d\n", skinData->GetNumPoints());
m_FileObj.write(_sTemp, string(_sTemp).size());
sprintf(_sTemp, "\tGetNumAssignedBones:\t%d\n", skinData->GetNumAssignedBones(0));// 骨骼数
m_FileObj.write(_sTemp, string(_sTemp).size());
sprintf(_sTemp, "\tGetAssignedBone:\t%d\n", skinData->GetAssignedBone(0,0));// 有分配的骨骼
m_FileObj.write(_sTemp, string(_sTemp).size());
// 各顶点权重:
for (int i = 0; i < skinData->GetNumPoints(); ++i)
{
int numOfBones = skinData->GetNumAssignedBones(i);
// 本顶点于各骨骼的权重
for (int boneAffectedId = 0; boneAffectedId < numOfBones;++boneAffectedId)
{
// 这里取到了权重__weight
float __weight = skinData->GetBoneWeight(i, boneAffectedId);
int boneIndex = skinData->GetAssignedBone( i , boneAffectedId);
//string strName = Util::TDuW2A( skin->GetBoneName(boneAffectedId) );
string strNameFromBoneIndex = Util::TDuW2A(skin->GetBoneName(boneIndex));
if(-1 != boneIndex)
{
sprintf(_sTemp, "\t\tBoneWeight:\t%d,%d:\t%f \t boneIndex:%d(%s)\n ", i, boneAffectedId, __weight,boneIndex , strNameFromBoneIndex);
m_FileObj.write(_sTemp, string(_sTemp).size());
}
}
/*float weight = skinData->GetBoneWeight(i, skinData->GetAssignedBone(0, 0));
sprintf(_sTemp, "\t\tBoneWeight:\t%d:%f\n", i , weight);
m_FileObj.write(_sTemp, string(_sTemp).size());*/
}
//sprintf(_sTemp, "\tGetBoneWeight:\t%f\n", skinData->GetBoneWeight(0, skinData->GetAssignedBone(0, 0)));
//m_FileObj.write(_sTemp, string(_sTemp).size());
}
#pragma region 顶点数据输出
string labelVData("\n顶点数据输出:\n");
m_FileObj.write(labelVData.c_str(), labelVData.size());
// 输出顶点数据 , 以能进一步研究顶点蒙皮数据的正确性.
// 1. 顶点的次序
// Order of the vertices. Get them counter clockwise if the objects is
// negatively scaled. This is important if an object has been mirrored.
Matrix3 tm = node->GetObjTMAfterWSM(0/*TimeValue*/);
BOOL negScale = getTMNegParity(tm);
int vx1, vx2, vx3;
if (negScale) {
vx1 = 2;
vx2 = 1;
vx3 = 0;
}
else {
vx1 = 0;
vx2 = 1;
vx3 = 2;
}
// Get mesh object
BOOL needDel;
ObjectState os = node->EvalWorldState(0);
TriObject* tri = getTriObjectFromObject(os.obj, 0/*TimeValue*/, needDel);
// Extract coords, normals, texture coords, vertex colors, and vertex normals
// from MAX mesh.
Mesh* mesh = &tri->GetMesh();
for (int _iv = 0; _iv < mesh->numVerts; ++_iv)
{
Point3 v1 = mesh->verts[_iv];
std::sprintf(_sTemp, "\tv1:%.4f\t%.4f\t%.4f\n", v1.x, v1.y, v1.z);
string strV1(_sTemp);
m_FileObj.write(strV1.c_str(), strV1.size());
}
#pragma endregion 顶点数据输出
string labelEnd("\n ES ES ES ES ES ES ES ES\n");
m_FileObj.write(labelEnd.c_str(), labelEnd.size());
}
`