The purpose is to make a custom export plug-in for OSG. Record the method of obtaining data
Max will provide an INode object in the code. Take all kinds of data from this object getSkin takes out the ISkin modifier The following function is also used to learn and output data to a text file
`
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 will only have skin if it has vertex data on September 10, 2018 { IDerivedObject *pDerivedObject; pDerivedObject = static_cast<IDerivedObject *>(pObject); // loop through all modifiers int stackId; Modifier *pModifier;// This is used to store the current modifier and try to turn it into a skin ISkin* _skin = NULL; for (stackId = 0; stackId < pDerivedObject->NumModifiers(); stackId++) { _skin = NULL; // get the modifier if (NULL == pDerivedObject->GetModifier(stackId)) { continue; } // skin is a modifier in Max, get this modifier, and then convert it to \ pModifier = pDerivedObject->GetModifier(stackId); // Arcadia 2018-09-10 if (pModifier) { char _sTemp[255]; // Context of skin data: _skin = dynamic_cast<ISkin*>(pModifier); if (_skin) { }// END if(_skin) } } return _skin; } return 0; }
`
Function readSkinData to parse skin data In the process of making Max export plug-in, it is convenient to debug by writing files Each vertex corresponds to several active bones. GetNumAssignedBones gets the active bones Then traverse to get each weight value of this vertex, and traverse to get the serial number of related bones
It should be noted that all bones are an array, and the action bones of a single vertex are another array, Using a single vertex to act on the subscript of a bone can get the subscript of a bone in [all bone arrays]
` /** *Read skin data and output to file for debugging and learning */ 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("Turn into ISkin\n", string("Turn into ISkin\n").size()); ISkinContextData *_data = skin->GetContextInterface(node); sprintf(_sTemp, "Point:\t%d\n", _data->GetNumPoints()); m_FileObj.write(_sTemp, string(_sTemp).size()); sprintf(_sTemp, "Skeleton number:\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) ); // On September 12, 2018, the return is skin invalid node PTR. I wonder if there will be any problem. Getskinninittm is OK, but GetBoneInitTM is not OK m_FileObj.write(_sTemp, string(_sTemp).size()); // Bone extraction: 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, "Skeleton name:\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 coordinate 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()); // Output coordinates of each vertex: // 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));// Skeleton number m_FileObj.write(_sTemp, string(_sTemp).size()); sprintf(_sTemp, "\tGetAssignedBone:\t%d\n", skinData->GetAssignedBone(0,0));// Assigned bones m_FileObj.write(_sTemp, string(_sTemp).size()); // Weight of each vertex: for (int i = 0; i < skinData->GetNumPoints(); ++i) { int numOfBones = skinData->GetNumAssignedBones(i); // Weight of this vertex on each bone for (int boneAffectedId = 0; boneAffectedId < numOfBones;++boneAffectedId) { // Here's the 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 vertex data output string labelVData("\n Vertex data output:\n"); m_FileObj.write(labelVData.c_str(), labelVData.size()); // Output vertex data to further study the correctness of vertex skin data // 1. Order of vertices // 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 vertex data output string labelEnd("\n ES ES ES ES ES ES ES ES\n"); m_FileObj.write(labelEnd.c_str(), labelEnd.size()); }
`