目的是爲OSG作自定義的導出插件. 記錄取得數據的方法.node
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<IDerivedObject *>(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<ISkin*>(pModifier); if (_skin) { }// END if(_skin) } } return _skin; } return 0; }
`oop
函數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()); }
`code