c++ - FBX node transform calculation -
recently, trying use fbx sdk import 3d model made 3dmax, got in trouble transformations. simple mesh(a sphere split in 2 halves) consisting of 2 nodes has 1 of it's nodes offset no matter what. tried several(quite ambiguous) ways of calculating transform latest sdk documentation provides... result same. i'll provide code , mesh in case can point out mistakes.
helper functions:
fbxamatrix meshmanager::getglobalposition(fbxnode* pnode, const fbxtime& ptime, fbxpose* ppose, fbxamatrix* pparentglobalposition) { fbxamatrix lglobalposition; bool lpositionfound = false; if (ppose) { int lnodeindex = ppose->find(pnode); if (lnodeindex > -1) { // bind pose global matrix. // if have rest pose, need check if // stored in global or local space. if (ppose->isbindpose() || !ppose->islocalmatrix(lnodeindex)) { lglobalposition = getposematrix(ppose, lnodeindex); } else { // have local matrix, need convert // global space matrix. fbxamatrix lparentglobalposition; if (pparentglobalposition) { lparentglobalposition = *pparentglobalposition; } else { if (pnode->getparent()) { lparentglobalposition = getglobalposition(pnode->getparent(), ptime, ppose); } } fbxamatrix llocalposition = getposematrix(ppose, lnodeindex); lglobalposition = lparentglobalposition * llocalposition; } lpositionfound = true; } } if (!lpositionfound) { // there no pose entry node, current global position instead. // ideally use parent global position , local position compute global position. // unfortunately equation // lglobalposition = pparentglobalposition * llocalposition // not hold when inheritance type other "parent" (rsrs). // compute parent rotation , scaling tricky in rrss , rrs cases. lglobalposition = pnode->evaluateglobaltransform(ptime); } return lglobalposition; } // matrix of given pose fbxamatrix meshmanager::getposematrix(fbxpose* ppose, int pnodeindex) { fbxamatrix lposematrix; fbxmatrix lmatrix = ppose->getmatrix(pnodeindex); memcpy((double*)lposematrix, (double*)lmatrix, sizeof(lmatrix.mdata)); return lposematrix; } // geometry offset node. never inherited children. fbxamatrix meshmanager::getgeometry(fbxnode* pnode) { const fbxvector4 lt = pnode->getgeometrictranslation(fbxnode::esourcepivot); const fbxvector4 lr = pnode->getgeometricrotation(fbxnode::esourcepivot); const fbxvector4 ls = pnode->getgeometricscaling(fbxnode::esourcepivot); return fbxamatrix(lt, lr, ls); } mat4 fbxmattoglm(const fbxamatrix& mat) { dvec4 c0 = glm::make_vec4((double*)mat.getcolumn(0).buffer()); dvec4 c1 = glm::make_vec4((double*)mat.getcolumn(1).buffer()); dvec4 c2 = glm::make_vec4((double*)mat.getcolumn(2).buffer()); dvec4 c3 = glm::make_vec4((double*)mat.getcolumn(3).buffer()); glm::mat4 convertmatr = mat4(c0, c1, c2, c3); return inverse(convertmatr); } mesh extraction:
void meshmanager::extractmeshrecursive(fbxscene* mscene, fbxnode* pnode, fbxamatrix& pparentglobalposition, shared_ptr<mesh> mesh, unsigned ¤tnode) { // find out type of node fbxnodeattribute* lnodeattribute = pnode->getnodeattribute(); fbxamatrix lglobalposition = getglobalposition(pnode, 1, mscene->getpose(-1) , &pparentglobalposition); fbxamatrix lgeometryoffset = getgeometry(pnode); fbxamatrix lglobaloffsetposition = lglobalposition * lgeometryoffset; if (lnodeattribute) { // actual node mesh data if mesh time // (you use sample draw other nodes cameras) if (lnodeattribute->getattributetype() == fbxnodeattribute::emesh) { // draw actual mesh data fbxmesh* lmesh = pnode->getmesh(); if (lmesh->istrianglemesh() == false) { fbxgeometryconverter conv(mfbxmanager); conv.triangulate(lnodeattribute, true); } const uint lvertexcount = lmesh->getcontrolpointscount(); const uint ltrianglecount = lmesh->getpolygoncount(); // may not have vertex data if (lvertexcount == 0) return; mesh->nodes.push_back(meshnode()); fbxvector4* pcontrolpoints = lmesh->getcontrolpoints(); (uint = 0; < lvertexcount; i++) { mesh->nodes[currentnode].vertices.push_back(vec3((float)pcontrolpoints[i].mdata[0], (float)pcontrolpoints[i].mdata[1], (float)pcontrolpoints[i].mdata[2])); } mesh->nodes[currentnode].localtransform = fbxmattoglm(lglobaloffsetposition); } currentnode++; } ... extracting other vertex attributes , materials ... // check if node has children attached const int lchildcount = pnode->getchildcount(); (int lchildindex = 0; lchildindex < lchildcount; ++lchildindex) { // draw child extractmeshrecursive(mscene, pnode->getchild(lchildindex), lglobalposition, mesh, currentnode); } }
incorrect part here:
mat4 fbxmattoglm(const fbxamatrix& mat) { dvec4 c0 = glm::make_vec4((double*)mat.getcolumn(0).buffer()); dvec4 c1 = glm::make_vec4((double*)mat.getcolumn(1).buffer()); dvec4 c2 = glm::make_vec4((double*)mat.getcolumn(2).buffer()); dvec4 c3 = glm::make_vec4((double*)mat.getcolumn(3).buffer()); glm::mat4 convertmatr = mat4(c0, c1, c2, c3); return inverse(convertmatr); // <--- incorrect } there no need inverse resulting matrix. should've been transposed instead. did @ first, unadjusted mesh scale huge couldn't see in renderer , started tinkering it. after putting millimeters unit's in 3d studio's fbx export window, transforms correct.


Comments
Post a Comment