FBXModel::VertexCollection FBXModel::getVertices(KFbxMesh* mesh) { const KFbxLayer* layer = mesh->GetLayer(0); const KFbxLayerElementNormal* normals = layer->GetNormals(); const KFbxLayerElementUV* texCoord = layer->GetUVs(); VertexCollection vertices = VertexCollection(mesh->GetControlPointsCount()); // positions for (unsigned i = 0; i < vertices.size(); i++) vertices[i].position = convert(mesh->GetControlPointAt(i)); // normals //if (normals) //{ // for (unsigned i = 0; i < vertices.size(); i++) // vertices[i].normal = Vector3::normalize(convert(normals->GetDirectArray().GetAt(i))); //} // UV if (texCoord) { for (int i = 0; i < mesh->GetPolygonCount(); ++i) for (int j = 0; j < mesh->GetPolygonSize(i); ++j) vertices[mesh->GetPolygonVertex(i, j)].texCoord = convert(texCoord->GetDirectArray().GetAt(mesh->GetTextureUVIndex(i,j))); } // skin weights std::vector<int> blendCount(vertices.size(), 0); for (int i = 0; i < mesh->GetDeformerCount(KFbxDeformer::eSKIN); ++i) { KFbxSkin* skin = (KFbxSkin*)mesh->GetDeformer(i, KFbxDeformer::eSKIN); for (int j = 0; j < skin->GetClusterCount(); ++j) { KFbxCluster* cluster = skin->GetCluster(j); unsigned boneIndex = bones[cluster->GetLink()->GetName()].index; int* vertexIndices = cluster->GetControlPointIndices(); double* vertexBlendWeights = cluster->GetControlPointWeights(); for (int k = 0; k < cluster->GetControlPointIndicesCount(); ++k) { int index = vertexIndices[k]; int blendIndex = blendCount[index]++; vertices[index].blendWeights[blendIndex] = (float)vertexBlendWeights[k]; vertices[index].blendIndices[blendIndex] = (unsigned char)boneIndex; } } } return vertices; }
void Model::ComputeSkinDeformation( KFbxMesh *mesh, KTime &time, KFbxVector4 *vertices, KFbxPose *pose ) { KFbxSkin *skin = (KFbxSkin*)mesh->GetDeformer( 0, KFbxDeformer::eSKIN ); KFbxSkin::ESkinningType skintype = skin->GetSkinningType(); int pooda; if( skintype == KFbxSkin::eLINEAR || skintype == KFbxSkin::eRIGID) { // linear pooda = 1; ComputeLinearDeformation( mesh, time, vertices, pose ); } else if( skintype == KFbxSkin::eDUALQUATERNION ) { // dual quaternion (?! :P) pooda = 2; } else if( skintype == KFbxSkin::eBLEND ) { pooda = 3; } }
BOOL ParseMeshSkinning( KFbxMesh* pMesh, SkinData* pSkinData ) { DWORD dwDeformerCount = pMesh->GetDeformerCount( KFbxDeformer::eSKIN ); if( dwDeformerCount == 0 ) return FALSE; ExportLog::LogMsg( 4, "Parsing skin weights on mesh %s", pMesh->GetName() ); const DWORD dwVertexCount = pMesh->GetControlPointsCount(); const DWORD dwStride = 4; pSkinData->Alloc( dwVertexCount, dwStride ); for( DWORD dwDeformerIndex = 0; dwDeformerIndex < dwDeformerCount; ++dwDeformerIndex ) { KFbxSkin* pSkin = (KFbxSkin*)pMesh->GetDeformer( dwDeformerIndex, KFbxDeformer::eSKIN ); DWORD dwClusterCount = pSkin->GetClusterCount(); for( DWORD dwClusterIndex = 0; dwClusterIndex < dwClusterCount; ++dwClusterIndex ) { KFbxCluster* pCluster = pSkin->GetCluster( dwClusterIndex ); DWORD dwClusterSize = pCluster->GetControlPointIndicesCount(); if( dwClusterSize == 0 ) continue; KFbxNode* pLink = pCluster->GetLink(); DWORD dwBoneIndex = pSkinData->GetBoneCount(); pSkinData->InfluenceNodes.push_back( pLink ); ExportLog::LogMsg( 4, "Influence %d: %s", dwBoneIndex, pLink->GetName() ); KFbxXMatrix matXBindPose; pCluster->GetTransformLinkMatrix( matXBindPose ); KFbxMatrix matBindPose = matXBindPose; CaptureBindPoseMatrix( pLink, matBindPose ); INT* pIndices = pCluster->GetControlPointIndices(); DOUBLE* pWeights = pCluster->GetControlPointWeights(); for( DWORD i = 0; i < dwClusterSize; ++i ) { pSkinData->InsertWeight( pIndices[i], dwBoneIndex, (FLOAT)pWeights[i] ); } } } return TRUE; }
osgDB::ReaderWriter::ReadResult OsgFbxReader::readMesh( KFbxNode* pNode, KFbxMesh* fbxMesh, std::vector<StateSetContent>& stateSetList, const char* szName) { GeometryMap geometryMap; osg::Geode* pGeode = new osg::Geode; pGeode->setName(szName); const KFbxLayerElementNormal* pFbxNormals = 0; const KFbxLayerElementVertexColor* pFbxColors = 0; const KFbxLayerElementMaterial* pFbxMaterials = 0; const KFbxVector4* pFbxVertices = fbxMesh->GetControlPoints(); // scan layers for Normals, Colors and Materials elements (this will get the first available elements)... for (int cLayerIndex = 0; cLayerIndex < fbxMesh->GetLayerCount(); cLayerIndex++) { const KFbxLayer* pFbxLayer = fbxMesh->GetLayer(cLayerIndex); if (!pFbxLayer) continue; // get normals, colors and materials... if (!pFbxNormals) pFbxNormals = pFbxLayer->GetNormals(); if (!pFbxColors) pFbxColors = pFbxLayer->GetVertexColors(); if (!pFbxMaterials) pFbxMaterials = pFbxLayer->GetMaterials(); } // look for UV elements (diffuse, opacity, reflection, emissive, ...) and get their channels names... std::string diffuseChannel = getUVChannelForTextureMap(stateSetList, KFbxSurfaceMaterial::sDiffuse); std::string opacityChannel = getUVChannelForTextureMap(stateSetList, KFbxSurfaceMaterial::sTransparentColor); std::string emissiveChannel = getUVChannelForTextureMap(stateSetList, KFbxSurfaceMaterial::sEmissive); // look for more UV elements here... // UV elements... const KFbxLayerElementUV* pFbxUVs_diffuse = getUVElementForChannel(diffuseChannel, KFbxLayerElement::eDIFFUSE_TEXTURES, fbxMesh); const KFbxLayerElementUV* pFbxUVs_opacity = getUVElementForChannel(opacityChannel, KFbxLayerElement::eTRANSPARENT_TEXTURES, fbxMesh); const KFbxLayerElementUV* pFbxUVs_emissive = getUVElementForChannel(emissiveChannel, KFbxLayerElement::eEMISSIVE_TEXTURES, fbxMesh); // more UV elements here... // check elements validity... if (!layerElementValid(pFbxNormals)) pFbxNormals = 0; if (!layerElementValid(pFbxColors)) pFbxColors = 0; if (!layerElementValid(pFbxUVs_diffuse)) pFbxUVs_diffuse = 0; if (!layerElementValid(pFbxUVs_opacity)) pFbxUVs_opacity = 0; if (!layerElementValid(pFbxUVs_emissive)) pFbxUVs_emissive = 0; // more here... int nPolys = fbxMesh->GetPolygonCount(); int nDeformerCount = fbxMesh->GetDeformerCount(KFbxDeformer::eSKIN); int nDeformerBlendShapeCount = fbxMesh->GetDeformerCount(KFbxDeformer::eBLENDSHAPE); GeometryType geomType = GEOMETRY_STATIC; //determine the type of geometry if (nDeformerCount) { geomType = GEOMETRY_RIG; } else if (nDeformerBlendShapeCount) { geomType = GEOMETRY_MORPH; } FbxToOsgVertexMap fbxToOsgVertMap; OsgToFbxNormalMap osgToFbxNormMap; // First add only triangles and quads (easy to split into triangles without // more processing) // This is the reason we store polygons references: PolygonRefList polygonRefList; for (int i = 0, nVertex = 0; i < nPolys; ++i) { int lPolygonSize = fbxMesh->GetPolygonSize(i); int materialIndex = getPolygonIndex(pFbxMaterials, i); osg::Geometry* pGeometry = getGeometry(pGeode, geometryMap, stateSetList, geomType, materialIndex, pFbxNormals != 0, pFbxUVs_diffuse != 0, pFbxUVs_opacity != 0, pFbxUVs_emissive != 0, // more UV elements here... pFbxColors != 0, options, lightmapTextures); osg::Array* pVertices = pGeometry->getVertexArray(); osg::Array* pNormals = pGeometry->getNormalArray(); // get texture coordinates... osg::Array* pTexCoords_diffuse = pGeometry->getTexCoordArray(StateSetContent::DIFFUSE_TEXTURE_UNIT); osg::Array* pTexCoords_opacity = pGeometry->getTexCoordArray(StateSetContent::OPACITY_TEXTURE_UNIT); osg::Array* pTexCoords_emissive = pGeometry->getTexCoordArray(StateSetContent::EMISSIVE_TEXTURE_UNIT); // more texture coordinates here... osg::Array* pColors = pGeometry->getColorArray(); if (lPolygonSize == 3) { // Triangle readMeshTriangle(fbxMesh, i, 0, 1, 2, nVertex, nVertex+1, nVertex+2, fbxToOsgVertMap, osgToFbxNormMap, pFbxVertices, pFbxNormals, pFbxUVs_diffuse, pFbxUVs_opacity, pFbxUVs_emissive, pFbxColors, pGeometry, pVertices, pNormals, pTexCoords_diffuse, pTexCoords_opacity, pTexCoords_emissive, pColors); nVertex += 3; } else if (lPolygonSize == 4) { // Quad - Convert to triangles // Use some fast specialized code to see how the should be decomposed // Two cases : Split at '02' (012 and 023), or split at '13 (013 and 123) bool split02 = quadSplit02(fbxMesh, i, 0, 1, 2, 3, pFbxVertices); int p02 = split02 ? 2 : 3; // Triangle 0, point 2 int p10 = split02 ? 0 : 1; // Triangle 1, point 0 readMeshTriangle(fbxMesh, i, 0, 1, p02, nVertex, nVertex+1, nVertex+p02, fbxToOsgVertMap, osgToFbxNormMap, pFbxVertices, pFbxNormals, pFbxUVs_diffuse, pFbxUVs_opacity, pFbxUVs_emissive, pFbxColors, pGeometry, pVertices, pNormals, pTexCoords_diffuse, pTexCoords_opacity, pTexCoords_emissive, pColors); readMeshTriangle(fbxMesh, i, p10, 2, 3, nVertex+p10, nVertex+2, nVertex+3, fbxToOsgVertMap, osgToFbxNormMap, pFbxVertices, pFbxNormals, pFbxUVs_diffuse, pFbxUVs_opacity, pFbxUVs_emissive, pFbxColors, pGeometry, pVertices, pNormals, pTexCoords_diffuse, pTexCoords_opacity, pTexCoords_emissive, pColors); nVertex += 4; } else if (tessellatePolygons) { // Polygons - Store to add after triangles polygonRefList.push_back(PolygonRef(pGeometry, i, nVertex)); nVertex += lPolygonSize; } else { int nVertex0 = nVertex; nVertex += (std::min)(2, lPolygonSize); for (int j = 2; j < lPolygonSize; ++j, ++nVertex) { readMeshTriangle(fbxMesh, i, 0, j - 1, j, nVertex0, nVertex - 1, nVertex, fbxToOsgVertMap, osgToFbxNormMap, pFbxVertices, pFbxNormals, pFbxUVs_diffuse, pFbxUVs_opacity, pFbxUVs_emissive, pFbxColors, pGeometry, pVertices, pNormals, pTexCoords_diffuse, pTexCoords_opacity, pTexCoords_emissive, pColors); } } } for (unsigned i = 0; i < pGeode->getNumDrawables(); ++i) { osg::Geometry* pGeometry = pGeode->getDrawable(i)->asGeometry(); osg::DrawArrays* pDrawArrays = new osg::DrawArrays( GL_TRIANGLES, 0, pGeometry->getVertexArray()->getNumElements()); pGeometry->addPrimitiveSet(pDrawArrays); } // Now add polygons - Convert to triangles // We put vertices in their own PrimitiveSet with Mode=POLYGON; then run the // Tessellator on the Geometry which should tessellate the polygons // automagically. for (PolygonRefList::iterator it = polygonRefList.begin(), itEnd=polygonRefList.end(); it != itEnd; ++it) { int i = it->numPoly; int lPolygonSize = fbxMesh->GetPolygonSize(i); //int materialIndex = getPolygonIndex(pFbxMaterials, i); osg::Geometry* pGeometry = it->pGeometry; osg::Array* pVertices = pGeometry->getVertexArray(); osg::Array* pNormals = pGeometry->getNormalArray(); osg::Array* pTexCoords_diffuse = pGeometry->getTexCoordArray(StateSetContent::DIFFUSE_TEXTURE_UNIT); osg::Array* pTexCoords_opacity = pGeometry->getTexCoordArray(StateSetContent::OPACITY_TEXTURE_UNIT); osg::Array* pTexCoords_emissive = pGeometry->getTexCoordArray(StateSetContent::EMISSIVE_TEXTURE_UNIT); osg::Array* pColors = pGeometry->getColorArray(); // Index of the 1st vertex of the polygon in the geometry int osgVertex0 = pVertices->getNumElements(); for (int j = 0, nVertex = it->nVertex; j<lPolygonSize; ++j, ++nVertex) { int v0 = fbxMesh->GetPolygonVertex(i, j); fbxToOsgVertMap.insert(FbxToOsgVertexMap::value_type(v0, GIPair(pGeometry, pVertices->getNumElements()))); addVec3ArrayElement(*pVertices, pFbxVertices[v0]); if (pNormals) { int n0 = getVertexIndex(pFbxNormals, fbxMesh, i, j, nVertex); osgToFbxNormMap.insert(OsgToFbxNormalMap::value_type(GIPair(pGeometry, pNormals->getNumElements()), n0)); addVec3ArrayElement(*pNormals, pFbxNormals->GetDirectArray().GetAt(n0)); } // add texture maps data (avoid duplicates)... if (pTexCoords_diffuse) { addVec2ArrayElement(*pTexCoords_diffuse, getElement(pFbxUVs_diffuse, fbxMesh, i, j, nVertex)); } if (pTexCoords_opacity && (pTexCoords_opacity != pTexCoords_diffuse)) { addVec2ArrayElement(*pTexCoords_opacity, getElement(pFbxUVs_opacity, fbxMesh, i, j, nVertex)); } // Only spherical reflection maps are supported (so do not add coordinates for the reflection map) if (pTexCoords_emissive && (pTexCoords_emissive != pTexCoords_opacity) && (pTexCoords_emissive != pTexCoords_diffuse)) { addVec2ArrayElement(*pTexCoords_emissive, getElement(pFbxUVs_emissive, fbxMesh, i, j, nVertex)); } // add more texture maps here... if (pColors) { addColorArrayElement(*pColors, getElement(pFbxColors, fbxMesh, i, j, nVertex)); } } osg::DrawArrays* pDrawArrays = new osg::DrawArrays( GL_POLYGON, osgVertex0, pGeometry->getVertexArray()->getNumElements() - osgVertex0); pGeometry->addPrimitiveSet(pDrawArrays); } for (unsigned i = 0; i < pGeode->getNumDrawables(); ++i) { osg::Geometry* pGeometry = pGeode->getDrawable(i)->asGeometry(); // Now split polygons if necessary osgUtil::Tessellator tessellator; tessellator.retessellatePolygons(*pGeometry); if (pGeode->getNumDrawables() > 1) { std::stringstream ss; ss << pGeode->getName() << " " << i + 1; pGeometry->setName(ss.str()); } else { pGeometry->setName(pGeode->getName()); } } if (geomType == GEOMETRY_RIG) { typedef std::map<osg::ref_ptr<osg::Geometry>, osg::ref_ptr<osgAnimation::RigGeometry> > GeometryRigGeometryMap; GeometryRigGeometryMap old2newGeometryMap; for (unsigned i = 0; i < pGeode->getNumDrawables(); ++i) { osg::Geometry* pGeometry = pGeode->getDrawable(i)->asGeometry(); osgAnimation::RigGeometry* pRig = new osgAnimation::RigGeometry; pRig->setSourceGeometry(pGeometry); pRig->copyFrom(*pGeometry); old2newGeometryMap.insert(GeometryRigGeometryMap::value_type( pGeometry, pRig)); pRig->setDataVariance(osg::Object::DYNAMIC); pRig->setUseDisplayList( false ); pGeode->setDrawable(i, pRig); pRig->setInfluenceMap(new osgAnimation::VertexInfluenceMap); pGeometry = pRig; } for (int i = 0; i < nDeformerCount; ++i) { KFbxSkin* pSkin = (KFbxSkin*)fbxMesh->GetDeformer(i, KFbxDeformer::eSKIN); int nClusters = pSkin->GetClusterCount(); for (int j = 0; j < nClusters; ++j) { KFbxCluster* pCluster = (KFbxCluster*)pSkin->GetCluster(j); //assert(KFbxCluster::eNORMALIZE == pCluster->GetLinkMode()); KFbxNode* pBone = pCluster->GetLink(); KFbxXMatrix transformLink; pCluster->GetTransformLinkMatrix(transformLink); KFbxXMatrix transformLinkInverse = transformLink.Inverse(); const double* pTransformLinkInverse = transformLinkInverse; osg::Matrix bindMatrix(pTransformLinkInverse); int nIndices = pCluster->GetControlPointIndicesCount(); int* pIndices = pCluster->GetControlPointIndices(); double* pWeights = pCluster->GetControlPointWeights(); for (int k = 0; k < nIndices; ++k) { int fbxIndex = pIndices[k]; float weight = static_cast<float>(pWeights[k]); for (FbxToOsgVertexMap::const_iterator it = fbxToOsgVertMap.find(fbxIndex); it != fbxToOsgVertMap.end() && it->first == fbxIndex; ++it) { GIPair gi = it->second; osgAnimation::RigGeometry& rig = dynamic_cast<osgAnimation::RigGeometry&>( *old2newGeometryMap[gi.first]); addBindMatrix(boneBindMatrices, pBone, bindMatrix, &rig); osgAnimation::VertexInfluenceMap& vim = *rig.getInfluenceMap(); osgAnimation::VertexInfluence& vi = getVertexInfluence(vim, pBone->GetName()); vi.push_back(osgAnimation::VertexIndexWeight( gi.second, weight)); } } } } } else if (geomType == GEOMETRY_MORPH) { for (unsigned i = 0; i < pGeode->getNumDrawables(); ++i) { osg::Geometry* pGeometry = pGeode->getDrawable(i)->asGeometry(); osgAnimation::MorphGeometry& morph = dynamic_cast<osgAnimation::MorphGeometry&>(*pGeometry); pGeode->addUpdateCallback(new osgAnimation::UpdateMorph(morph.getName())); //read morph geometry for (int nBlendShape = 0; nBlendShape < nDeformerBlendShapeCount; ++nBlendShape) { KFbxBlendShape* pBlendShape = KFbxCast<KFbxBlendShape>(fbxMesh->GetDeformer(nBlendShape, KFbxDeformer::eBLENDSHAPE)); const int nBlendShapeChannelCount = pBlendShape->GetBlendShapeChannelCount(); for (int nBlendShapeChannel = 0; nBlendShapeChannel < nBlendShapeChannelCount; ++nBlendShapeChannel) { KFbxBlendShapeChannel* pBlendShapeChannel = pBlendShape->GetBlendShapeChannel(nBlendShapeChannel); if (!pBlendShapeChannel->GetTargetShapeCount()) continue; //Assume one shape if (pBlendShapeChannel->GetTargetShapeCount() > 1) { OSG_WARN << "Multiple FBX Target Shapes, only the first will be used" << std::endl; } const KFbxGeometryBase* pMorphShape = pBlendShapeChannel->GetTargetShape(0); const KFbxLayerElementNormal* pFbxShapeNormals = 0; if (const KFbxLayer* pFbxShapeLayer = pMorphShape->GetLayer(0)) { pFbxShapeNormals = pFbxShapeLayer->GetNormals(); if (!layerElementValid(pFbxShapeNormals)) pFbxShapeNormals = 0; } osg::Geometry* pMorphTarget = new osg::Geometry(morph); pMorphTarget->setVertexArray(static_cast<osg::Array*>( pMorphTarget->getVertexArray()->clone(osg::CopyOp::DEEP_COPY_ARRAYS))); if (pFbxShapeNormals) { if (osg::Array* pNormals = pMorphTarget->getNormalArray()) { pMorphTarget->setNormalArray(static_cast<osg::Array*>( pNormals->clone(osg::CopyOp::DEEP_COPY_ARRAYS))); } } pMorphTarget->setName(pMorphShape->GetName()); morph.addMorphTarget(pMorphTarget, 0.0f); readAnimation(pNode, fbxScene, morph.getName(), pAnimationManager, fbxMesh, nBlendShape, nBlendShapeChannel, (int)morph.getMorphTargetList().size() - 1); } } } int nMorphTarget = 0; for (int nBlendShape = 0; nBlendShape < nDeformerBlendShapeCount; ++nBlendShape) { KFbxBlendShape* pBlendShape = KFbxCast<KFbxBlendShape>(fbxMesh->GetDeformer(nBlendShape, KFbxDeformer::eBLENDSHAPE)); const int nBlendShapeChannelCount = pBlendShape->GetBlendShapeChannelCount(); for (int nBlendShapeChannel = 0; nBlendShapeChannel < nBlendShapeChannelCount; ++nBlendShapeChannel) { KFbxBlendShapeChannel* pBlendShapeChannel = pBlendShape->GetBlendShapeChannel(nBlendShapeChannel); if (!pBlendShapeChannel->GetTargetShapeCount()) continue; //Assume one shape again const KFbxGeometryBase* pMorphShape = pBlendShapeChannel->GetTargetShape(0); const KFbxLayerElementNormal* pFbxShapeNormals = 0; if (const KFbxLayer* pFbxShapeLayer = pMorphShape->GetLayer(0)) { pFbxShapeNormals = pFbxShapeLayer->GetNormals(); if (!layerElementValid(pFbxShapeNormals)) pFbxShapeNormals = 0; } const KFbxVector4* pControlPoints = pMorphShape->GetControlPoints(); int nControlPoints = pMorphShape->GetControlPointsCount(); for (int fbxIndex = 0; fbxIndex < nControlPoints; ++fbxIndex) { osg::Vec3d vPos = convertVec3(pControlPoints[fbxIndex]); for (FbxToOsgVertexMap::const_iterator it = fbxToOsgVertMap.find(fbxIndex); it != fbxToOsgVertMap.end() && it->first == fbxIndex; ++it) { GIPair gi = it->second; osgAnimation::MorphGeometry& morphGeom = dynamic_cast<osgAnimation::MorphGeometry&>(*gi.first); osg::Geometry* pGeometry = morphGeom.getMorphTarget(nMorphTarget).getGeometry(); if (pGeometry->getVertexArray()->getType() == osg::Array::Vec3dArrayType) { osg::Vec3dArray* pVertices = static_cast<osg::Vec3dArray*>(pGeometry->getVertexArray()); (*pVertices)[gi.second] = vPos; } else { osg::Vec3Array* pVertices = static_cast<osg::Vec3Array*>(pGeometry->getVertexArray()); (*pVertices)[gi.second] = vPos; } if (pFbxShapeNormals && pGeometry->getNormalArray()) { if (pGeometry->getNormalArray()->getType() == osg::Array::Vec3dArrayType) { osg::Vec3dArray* pNormals = static_cast<osg::Vec3dArray*>(pGeometry->getNormalArray()); (*pNormals)[gi.second] = convertVec3( pFbxShapeNormals->GetDirectArray().GetAt(osgToFbxNormMap[gi])); } else { osg::Vec3Array* pNormals = static_cast<osg::Vec3Array*>(pGeometry->getNormalArray()); (*pNormals)[gi.second] = convertVec3( pFbxShapeNormals->GetDirectArray().GetAt(osgToFbxNormMap[gi])); } } } } //don't put this in the for loop as we don't want to do it if the loop continues early ++nMorphTarget; } } } KFbxXMatrix fbxGeometricTransform; fbxGeometricTransform.SetTRS( pNode->GeometricTranslation.Get(), pNode->GeometricRotation.Get(), pNode->GeometricScaling.Get()); const double* pGeometricMat = fbxGeometricTransform; osg::Matrix osgGeometricTransform(pGeometricMat); if (geomType == GEOMETRY_RIG) { KFbxSkin* pSkin = (KFbxSkin*)fbxMesh->GetDeformer(0, KFbxDeformer::eSKIN); if (pSkin->GetClusterCount()) { KFbxXMatrix fbxTransformMatrix; pSkin->GetCluster(0)->GetTransformMatrix(fbxTransformMatrix); const double* pTransformMatrix = fbxTransformMatrix; osgGeometricTransform.postMult(osg::Matrix(pTransformMatrix)); } } osg::Node* pResult = pGeode; if (!osgGeometricTransform.isIdentity()) { osg::MatrixTransform* pMatTrans = new osg::MatrixTransform(osgGeometricTransform); pMatTrans->addChild(pGeode); pResult = pMatTrans; } if (geomType == GEOMETRY_RIG) { //Add the geometry to the skeleton ancestor of one of the bones. KFbxSkin* pSkin = (KFbxSkin*)fbxMesh->GetDeformer(0, KFbxDeformer::eSKIN); if (pSkin->GetClusterCount()) { osgAnimation::Skeleton* pSkeleton = getSkeleton( pSkin->GetCluster(0)->GetLink(), fbxSkeletons, skeletonMap); pSkeleton->addChild(pResult); return osgDB::ReaderWriter::ReadResult::FILE_LOADED; } } return osgDB::ReaderWriter::ReadResult(pResult); }