void GameEngine::FbxLoader::FbxLoader::ProcessAnimCurveR(FbxAnimCurve* curve[3], AnimTransformCurve& animCurve, FbxAMatrix & preRotation) { if(!curve) return; auto& curve3 = animCurve.rotation; int xKeys = curve[0]->KeyGetCount(); int yKeys = curve[1]->KeyGetCount(); int zKeys = curve[2]->KeyGetCount(); // check key sync if(xKeys != yKeys || xKeys != zKeys) return; int nKeys = xKeys; curve3.curves[0].keyframes.resize(nKeys); curve3.curves[1].keyframes.resize(nKeys); curve3.curves[2].keyframes.resize(nKeys); animCurve.end = (float)curve[0]->KeyGetTime(nKeys - 1).GetSecondDouble(); for(int ki = 0; ki < nKeys; ++ki) { auto& xkey = curve3.curves[0].keyframes[ki]; auto& ykey = curve3.curves[1].keyframes[ki]; auto& zkey = curve3.curves[2].keyframes[ki]; curve[0]->KeySetTangentMode(ki, FbxAnimCurveDef::eTangentAuto); curve[1]->KeySetTangentMode(ki, FbxAnimCurveDef::eTangentAuto); curve[2]->KeySetTangentMode(ki, FbxAnimCurveDef::eTangentAuto); auto xvalue = curve[0]->KeyGetValue(ki); auto yvalue = curve[1]->KeyGetValue(ki); auto zvalue = curve[2]->KeyGetValue(ki); auto xlt = curve[0]->KeyGetLeftAuto(ki); auto xrt = curve[0]->KeyGetRightAuto(ki); auto ylt = curve[1]->KeyGetLeftAuto(ki); auto yrt = curve[1]->KeyGetRightAuto(ki); auto zlt = curve[2]->KeyGetLeftAuto(ki); auto zrt = curve[2]->KeyGetRightAuto(ki); FbxAMatrix temp; temp.SetR(FbxVector4(xvalue, yvalue, zvalue)); auto R = (preRotation* temp).GetR(); xvalue = (float)R[0]; yvalue = (float)R[1]; zvalue = (float)R[2]; float t = (float)curve[0]->KeyGetTime(ki).GetSecondDouble(); if(axismode == eLeftHanded) { yvalue *= -1; ylt *= -1; yrt *= -1; zvalue *= -1; zlt *= -1; zrt *= -1; } xkey.time = t; ykey.time = t; zkey.time = t; xkey.value = xvalue; ykey.value = yvalue; zkey.value = zvalue; xkey.leftTangent = xlt; xkey.rightTangent = xrt; ykey.leftTangent = ylt; ykey.rightTangent = yrt; zkey.leftTangent = zlt; zkey.rightTangent = zrt; } }
/* The result of this function is a matrix which transforms the verts from their position (where they were when the skeleton was bound to them) to the space of the bone when the verts were bound. We can then append the bone's current transform in the animation to get the verts into worls space at the current point in the animation. */ void Cluster::computeClusterInitTransforms(FbxMesh* mesh, FbxCluster* cluster) { FbxCluster::ELinkMode lClusterMode = cluster->GetLinkMode(); FbxAMatrix lReferenceGlobalInitPosition; FbxAMatrix lAssociateGlobalInitPosition; FbxAMatrix lClusterGlobalInitPosition; FbxAMatrix lClusterGeometry; FbxAMatrix lReferenceGeometry; if (lClusterMode == FbxCluster::eAdditive && cluster->GetAssociateModel()) { throw "Addative skinning mode not supported"; } else { // Transform from the verts' local position at bind time (which is their position when loaded from file) to world space. cluster->GetTransformMatrix(lReferenceGlobalInitPosition); lReferenceGeometry = getGeometry(mesh->GetNode()); lReferenceGlobalInitPosition *= lReferenceGeometry; // Get the link initial global position and the link current global position. cluster->GetTransformLinkMatrix(lClusterGlobalInitPosition); // Transform from world space to bones space at binding time FbxAMatrix globalInitPosInv = lClusterGlobalInitPosition.Inverse(); FbxAMatrix initTransform = globalInitPosInv * lReferenceGlobalInitPosition; meshToBoneTransform = Matrix44<float>( initTransform[0][0], initTransform[0][1], initTransform[0][2], initTransform[0][3], initTransform[1][0], initTransform[1][1], initTransform[1][2], initTransform[1][3], initTransform[2][0], initTransform[2][1], initTransform[2][2], initTransform[2][3], initTransform[3][0], initTransform[3][1], initTransform[3][2], initTransform[3][3]); } }
void MeshEntry::LoadTransform(FbxMesh *mesh) { FbxVector4 T = mesh->GetNode()->GetGeometricTranslation (FbxNode::eSourcePivot); FbxVector4 R = mesh->GetNode()->GetGeometricRotation(FbxNode::eSourcePivot); FbxVector4 S = mesh->GetNode()->GetGeometricScaling(FbxNode::eSourcePivot); FbxAMatrix geometric_offset_transform(T, R, S); FbxAMatrix transform = mesh->GetNode()->GetScene()->GetAnimationEvaluator()->GetNodeGlobalTransform(mesh->GetNode()) * geometric_offset_transform; for (qint32 i = 0; i < 4; i++) for (qint32 j = 0; j < 4; j++) m_local_transform(i, j) = transform.Transpose().Get(i, j); }
void FBXSceneEncoder::transformNode(FbxNode* fbxNode, Node* node) { FbxAMatrix matrix; float m[16]; if (fbxNode->GetCamera() || fbxNode->GetLight()) { FbxAMatrix rotateAdjust; if(fbxNode->GetLight()) { /* * according to the fbx-documentation the light's forward vector * points along a node's negative Y axis. * so we have to rotate it by 90° around the X-axis to correct it. */ if(fbxNode->RotationActive.Get()) { const FbxVector4& postRotation = fbxNode->PostRotation.Get(); fbxNode->SetPostRotation(FbxNode::eSourcePivot, FbxVector4(postRotation.mData[0] + 90.0, postRotation.mData[1], postRotation.mData[2]) ); } else { // if the rotation is deactivated we have to rotate it anyway to get the correct transformation in the end rotateAdjust.SetR(FbxVector4(-90.0, 0.0, 0.0)); } matrix = fbxNode->EvaluateLocalTransform() * rotateAdjust; } else if(fbxNode->GetCamera()) { // TODO: use the EvaluateLocalTransform() function for the transformations for the camera /* * the current implementation ignores pre- and postrotation among others (usually happens with fbx-export from blender) * * Some info for a future implementation: * according to the fbx-documentation the camera's forward vector * points along a node's positive X axis. * so we have to correct it if we use the EvaluateLocalTransform-function * just rotating it by 90° around the Y axis (similar to above) doesn't work */ matrix.SetTRS(fbxNode->LclTranslation.Get(), fbxNode->LclRotation.Get(), fbxNode->LclScaling.Get()); } copyMatrix(matrix, m); node->setTransformMatrix(m); } else { matrix = fbxNode->EvaluateLocalTransform(); copyMatrix(matrix, m); node->setTransformMatrix(m); } }
FbxAMatrix LoaderFbxMesh::getGeometry(FbxNode* node) { FbxAMatrix fbxGeometry; FbxVector4 fbxTranslation, fbxRotation, fbxScaling; fbxTranslation = node->GetGeometricTranslation(FbxNode::eSourcePivot); fbxRotation = node->GetGeometricRotation(FbxNode::eSourcePivot); fbxScaling = node->GetGeometricScaling(FbxNode::eSourcePivot); fbxGeometry.SetTRS(fbxTranslation, fbxRotation, fbxScaling); return fbxGeometry; }
void FbxFileLoader::print_matrix( const FbxAMatrix& m ) const { std::cout.setf( std::ios_base::fixed, std::ios_base::floatfield ); std::cout.precision( 4 ); std::cout << "\tT : " << m.GetT()[ 0 ] << ", " << m.GetT()[ 1 ] << ", " << m.GetT()[ 2 ] << std::endl; std::cout << "\tR : " << m.GetR()[ 0 ] << ", " << m.GetR()[ 1 ] << ", " << m.GetR()[ 2 ] << std::endl; std::cout << "\tS : " << m.GetS()[ 0 ] << ", " << m.GetS()[ 1 ] << ", " << m.GetS()[ 2 ] << std::endl; }
bool ParseMeshSkinning( FbxMesh* pMesh, SkinData* pSkinData ) { DWORD dwDeformerCount = pMesh->GetDeformerCount( FbxDeformer::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 ) { auto pSkin = reinterpret_cast<FbxSkin*>( pMesh->GetDeformer( dwDeformerIndex, FbxDeformer::eSkin ) ); DWORD dwClusterCount = pSkin->GetClusterCount(); for( DWORD dwClusterIndex = 0; dwClusterIndex < dwClusterCount; ++dwClusterIndex ) { auto pCluster = pSkin->GetCluster( dwClusterIndex ); DWORD dwClusterSize = pCluster->GetControlPointIndicesCount(); if( dwClusterSize == 0 ) continue; auto pLink = pCluster->GetLink(); DWORD dwBoneIndex = pSkinData->GetBoneCount(); pSkinData->InfluenceNodes.push_back( pLink ); ExportLog::LogMsg( 4, "Influence %u: %s", dwBoneIndex, pLink->GetName() ); FbxAMatrix matXBindPose; pCluster->GetTransformLinkMatrix( matXBindPose ); FbxAMatrix matReferenceGlobalInitPosition; pCluster->GetTransformMatrix(matReferenceGlobalInitPosition); FbxMatrix matBindPose = matReferenceGlobalInitPosition.Inverse() * 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; }
FTransform FFbxDataConverter::ConvertTransform(FbxAMatrix Matrix) { FTransform Out; FQuat Rotation = ConvertRotToQuat(Matrix.GetQ()); FVector Origin = ConvertPos(Matrix.GetT()); FVector Scale = ConvertScale(Matrix.GetS()); Out.SetTranslation(Origin); Out.SetScale3D(Scale); Out.SetRotation(Rotation); return Out; }
FbxAMatrix LoaderFbxMesh::convertToLeftHanded(FbxAMatrix fbxMatrix) { FbxAMatrix convertionMatrix; FbxVector4 rowX(1.0, 0.0, 0.0, 0.0); FbxVector4 rowY(0.0, 1.0, 0.0, 0.0); FbxVector4 rowZ(0.0, 0.0, -1.0, 0.0); FbxVector4 rowW(0.0, 0.0, 0.0, 1.0); convertionMatrix.SetRow(0, rowX); convertionMatrix.SetRow(1, rowY); convertionMatrix.SetRow(2, rowZ); convertionMatrix.SetRow(3, rowW); FbxAMatrix convertedMatrix = fbxMatrix * convertionMatrix; return convertedMatrix; }
FMatrix FFbxDataConverter::ConvertMatrix(FbxAMatrix Matrix) { FMatrix UEMatrix; for(int i=0; i<4; ++i) { FbxVector4 Row = Matrix.GetRow(i); if(i==1) { UEMatrix.M[i][0] = -Row[0]; UEMatrix.M[i][1] = Row[1]; UEMatrix.M[i][2] = -Row[2]; UEMatrix.M[i][3] = -Row[3]; } else { UEMatrix.M[i][0] = Row[0]; UEMatrix.M[i][1] = -Row[1]; UEMatrix.M[i][2] = Row[2]; UEMatrix.M[i][3] = Row[3]; } } return UEMatrix; }
void fbxLoader2::setBindPoseCluster(FbxNode *node) { if( node->GetNodeAttribute()) { switch(node->GetNodeAttribute()->GetAttributeType()) { case FbxNodeAttribute::eMesh: FbxMesh *mesh = node->GetMesh(); for (int j = 0; j<mesh->GetDeformerCount(); j++) { FbxSkin *skin = (FbxSkin*) mesh->GetDeformer(j,FbxDeformer::eSkin); int clusters = skin->GetClusterCount(); for(int k = 0; k<clusters; k++) { FbxCluster* cluster = skin->GetCluster(k); FbxNode* boneLink = cluster->GetLink(); if(boneLink) { std::string nameLink = boneLink->GetName(); FbxAMatrix translationM; FbxAMatrix invert; cluster->GetTransformLinkMatrix(translationM); cluster->GetTransformMatrix(invert); translationM = translationM * invert.Inverse(); D3DXMATRIX mat = D3DXMATRIX((float)translationM.mData[0].mData[0], (float)translationM.mData[0].mData[1], (float)translationM.mData[0].mData[2], (float)translationM.mData[3].mData[0], (float)translationM.mData[1].mData[0], (float)translationM.mData[1].mData[1], (float)translationM.mData[1].mData[2], (float)translationM.mData[3].mData[1], (float)translationM.mData[2].mData[0], (float)translationM.mData[2].mData[1], (float)translationM.mData[2].mData[2], (float)translationM.mData[3].mData[2], 0,0,0,1); skeleton->GetBone(skeleton->GetBoneByName(nameLink))->SetTransformation(mat); } } } break; } } for (int i = 0; i<node->GetChildCount(); i++) { FbxNode* child = node->GetChild(i); setBindPoseCluster(child); } }
void FBXSceneEncoder::loadSkin(FbxMesh* fbxMesh, Model* model) { const int deformerCount = fbxMesh->GetDeformerCount(); for (int i = 0; i < deformerCount; ++i) { FbxDeformer* deformer = fbxMesh->GetDeformer(i); if (deformer->GetDeformerType() == FbxDeformer::eSkin) { FbxSkin* fbxSkin = FbxCast<FbxSkin>(deformer); MeshSkin* skin = new MeshSkin(); vector<string> jointNames; vector<Node*> joints; vector<Matrix> bindPoses; const int clusterCount = fbxSkin->GetClusterCount(); for (int j = 0; j < clusterCount; ++j) { FbxCluster* cluster = fbxSkin->GetCluster(j); assert(cluster); FbxNode* linkedNode = cluster->GetLink(); if (linkedNode && linkedNode->GetSkeleton()) { const char* jointName = linkedNode->GetName(); assert(jointName); jointNames.push_back(jointName); Node* joint = loadNode(linkedNode); assert(joint); joints.push_back(joint); FbxAMatrix matrix; cluster->GetTransformLinkMatrix(matrix); Matrix m; copyMatrix(matrix.Inverse(), m); bindPoses.push_back(m); } } skin->setJointNames(jointNames); skin->setJoints(joints); skin->setBindPoses(bindPoses); model->setSkin(skin); break; } } }
FbxMatrix FBXScene::GetGeometricOffset2(FbxNode* pNode) { if( !pNode ) { FbxAMatrix mat; mat.SetIdentity(); return mat; } // CheckMe: E Source Set = E Source Pivot? FbxVector4 T = pNode->GetGeometricTranslation(FbxNode::eSourcePivot); FbxVector4 R = pNode->GetGeometricRotation(FbxNode::eSourcePivot); FbxVector4 S = pNode->GetGeometricScaling(FbxNode::eSourcePivot); FbxAMatrix matFBXGeometryOffset; matFBXGeometryOffset.SetIdentity(); matFBXGeometryOffset.SetTRS(T,R,S); return matFBXGeometryOffset; }
CU::Matrix44f CreateMatrix(FbxAMatrix& aOriention) { CU::Matrix44f returnMatrix; for(int y = 0;y < 4;++y) { for(int x = 0;x < 4;++x) { returnMatrix.myMatrix[y * 4 + x] = (float)aOriention.Get(x, y); } } return returnMatrix; }
FbxAMatrix LoaderFbxMesh::parseTransformMatrix_debug(FbxCluster* cluster, FbxMesh* mesh, FbxPose* fbxPose, FbxAMatrix globalPosition) { FbxAMatrix transform; FbxAMatrix bindPoseTransform; FbxAMatrix bindPoseTransformInverse; FbxAMatrix boneReferenceTransform; FbxAMatrix boneReferenceTransformInverse; FbxAMatrix meshGeometryMatrix; cluster->GetTransformLinkMatrix(bindPoseTransform); cluster->GetTransformMatrix(boneReferenceTransform); bindPoseTransformInverse = bindPoseTransform.Inverse(); boneReferenceTransformInverse = boneReferenceTransform.Inverse(); meshGeometryMatrix = getGeometry(mesh->GetNode()); transform = bindPoseTransformInverse * boneReferenceTransform; return transform; }
FbxAMatrix LoaderFbxMesh::parseTransformMatrixOther(FbxCluster* cluster, FbxMesh* mesh, FbxPose* fbxPose, FbxAMatrix globalPosition) { FbxAMatrix referenceGeometry; FbxAMatrix referenceGlobalInitPosition; FbxAMatrix referenceGlobalCurrentPosition; FbxAMatrix clusterGeometry; FbxAMatrix clusterGlobalInitPosition; FbxAMatrix clusterGlobalCurrentPosition; FbxAMatrix clusterRelativeInitPosition; FbxAMatrix clusterRelativeCurrentPositionInverse; FbxTime time(0); FbxAMatrix fbxMatrixIdentity; fbxMatrixIdentity.SetIdentity(); cluster->GetTransformMatrix(referenceGlobalInitPosition); referenceGlobalCurrentPosition = globalPosition; referenceGeometry = getGeometry(mesh->GetNode()); referenceGlobalInitPosition *= referenceGeometry; cluster->GetTransformLinkMatrix(clusterGlobalInitPosition); clusterGlobalCurrentPosition = getGlobalPosition(cluster->GetLink(), time, fbxPose, nullptr); clusterRelativeInitPosition = clusterGlobalInitPosition.Inverse() * referenceGlobalInitPosition; clusterRelativeCurrentPositionInverse = referenceGlobalCurrentPosition.Inverse() * clusterGlobalCurrentPosition; FbxAMatrix offsetMatrix; offsetMatrix = clusterRelativeCurrentPositionInverse * clusterRelativeInitPosition; return offsetMatrix; }
void FbxLoader::ComputeNodeMatrix(FbxNode* node, Node& meshNode, bool local) { if(!node) return; FbxAnimEvaluator* evaluator = scene->GetAnimationEvaluator(); FbxAMatrix global; global.SetIdentity(); FbxTime time; time.SetSecondDouble(0.0); if(node != scene->GetRootNode()) { if(local) { global = evaluator->GetNodeLocalTransform(node, time); } else { global = evaluator->GetNodeGlobalTransform(node, time); } } auto T = global.GetT() * factor; if(axismode == eLeftHanded) { auto R = global.GetR(); R[1] *= -1; R[2] *= -1; T[0] *= -1; global.SetR(R); } global.SetT(T); meshNode.matrix = Matrix( (float)global[0][0], (float)global[0][1], (float)global[0][2], (float)global[0][3], (float)global[1][0], (float)global[1][1], (float)global[1][2], (float)global[1][3], (float)global[2][0], (float)global[2][1], (float)global[2][2], (float)global[2][3], (float)global[3][0], (float)global[3][1], (float)global[3][2], (float)global[3][3]); }
//---------------------------------------------------------------------------- HMatrix Utilities::FbxMatrixToPX2(FbxAMatrix &fbxMat) { HMatrix mat; for (int row = 0; row < 4; row++) { for (int col = 0; col < 4; col++) { mat(col, row) = (float)fbxMat.Get(row, col); } } return mat; }
FbxAMatrix LoaderFbxMesh::parseTransformMatrixAssociateModel(FbxCluster* cluster, FbxMesh* mesh, FbxPose* fbxPose, FbxAMatrix globalPosition) { FbxAMatrix associateGeometry; FbxAMatrix associateGlobalInitPosition; FbxAMatrix associateGlobalCurrentPosition; FbxAMatrix referenceGeometry; FbxAMatrix referenceGlobalInitPosition; FbxAMatrix referenceGlobalCurrentPosition; FbxAMatrix clusterGeometry; FbxAMatrix clusterGlobalInitPosition; FbxAMatrix clusterGlobalCurrentPosition; FbxTime time(0); cluster->GetTransformAssociateModelMatrix(associateGlobalInitPosition); associateGeometry = getGeometry(cluster->GetAssociateModel()); associateGlobalInitPosition *= associateGeometry; associateGlobalCurrentPosition = getGlobalPosition(cluster->GetAssociateModel(), time, fbxPose, nullptr); cluster->GetTransformMatrix(referenceGlobalInitPosition); referenceGeometry = getGeometry(mesh->GetNode()); referenceGlobalInitPosition *= referenceGeometry; referenceGlobalCurrentPosition = globalPosition; cluster->GetTransformLinkMatrix(clusterGlobalInitPosition); clusterGeometry = getGeometry(cluster->GetLink()); clusterGlobalInitPosition *= clusterGeometry; clusterGlobalCurrentPosition = getGlobalPosition(cluster->GetLink(), time, fbxPose, nullptr); FbxAMatrix offsetMatrix; offsetMatrix = referenceGlobalInitPosition.Inverse() * associateGlobalInitPosition * associateGlobalCurrentPosition.Inverse() * clusterGlobalCurrentPosition * clusterGlobalInitPosition.Inverse() * referenceGlobalInitPosition; return offsetMatrix; }
void FbxParser::ProcessLight(FbxNode* pNode, std::vector<GS::Light*>& lights) { FbxLight* llight = (FbxLight*) pNode->GetNodeAttribute(); if (!llight) return ; // Get the light color. FbxDouble3 c = llight->Color.Get(); GS::float4 lcolor( c[0], c[1], c[2], 1.0 ); float intensity = llight->Intensity.Get(); if (intensity) lcolor= lcolor*(intensity/100); // to do so far, we only process directional light if (llight->LightType.Get() == FbxLight::eDirectional) { //FbxDouble3 dir = pNode->LclRotation.Get(); FbxAnimEvaluator* lEvaluator = mpFbxScene->GetAnimationEvaluator(); FbxAMatrix lGlobal; lGlobal= lEvaluator->GetNodeGlobalTransform( pNode); FbxVector4 rotation = lGlobal.GetR(); FbxVector4 tran = lGlobal.GetT(); FbxQuaternion quaternion = lGlobal.GetQ(); GS::float4 q(quaternion[0], quaternion[1], quaternion[2],quaternion[3]); GS::float4x4 rotMat = GS::quat_rotation_matrix(q); GS::float4 dir(mul(rotMat, GS::float4(0, 0, -1, 1))); /* dir(0,0,-1); FbxQuaternion quaternion = lGlobal.GetQ(); quaternion. LcLRotation3f quaternion3f(quaternion[0], quaternion[1], quaternion[2], quaternion[3]); LcLTransform3f rot3f(quaternion3f); LcLVec3f rot_dir = dir * rot3f;*/ } }
// Deform the vertex array in classic linear way. void fbxLoader2::ComputeLinearDeformation(FbxAMatrix& pGlobalPosition, FbxMesh* pMesh, FbxTime& pTime, FbxPose* pPose, int frame) { // All the links must have the same link mode. FbxCluster::ELinkMode lClusterMode = ((FbxSkin*)pMesh->GetDeformer(0, FbxDeformer::eSkin))->GetCluster(0)->GetLinkMode(); int lVertexCount = pMesh->GetControlPointsCount(); FbxAMatrix* lClusterDeformation = new FbxAMatrix[lVertexCount]; memset(lClusterDeformation, 0, lVertexCount * sizeof(FbxAMatrix)); double* lClusterWeight = new double[lVertexCount]; memset(lClusterWeight, 0, lVertexCount * sizeof(double)); if (lClusterMode == FbxCluster::eAdditive) { for (int i = 0; i < lVertexCount; ++i) { lClusterDeformation[i].SetIdentity(); } } // For all skins and all clusters, accumulate their deformation and weight // on each vertices and store them in lClusterDeformation and lClusterWeight. int lSkinCount = pMesh->GetDeformerCount(FbxDeformer::eSkin); for ( int lSkinIndex=0; lSkinIndex<lSkinCount; ++lSkinIndex) { FbxSkin * lSkinDeformer = (FbxSkin *)pMesh->GetDeformer(lSkinIndex, FbxDeformer::eSkin); int lClusterCount = lSkinDeformer->GetClusterCount(); for ( int lClusterIndex=0; lClusterIndex<lClusterCount; ++lClusterIndex) { FbxCluster* lCluster = lSkinDeformer->GetCluster(lClusterIndex); if (!lCluster->GetLink()) continue; FbxAMatrix lVertexTransformMatrix; ComputeClusterDeformation(pGlobalPosition, pMesh, lCluster, lVertexTransformMatrix, pTime, pPose, frame); //lVertexTransformMatrix.Transpose(); FbxAMatrix identityM; identityM.SetIdentity(); FbxVector4 rotation = lVertexTransformMatrix.GetROnly(); FbxVector4 translation = lVertexTransformMatrix.GetT(); FbxVector4 scaling = lVertexTransformMatrix.GetS(); //rotation = FbxVector4(rotation.mData[0], rotation.mData[1], rotation.mData[2], rotation.mData[3]); //translation = FbxVector4 (translation.mData[0], translation.mData[1], translation.mData[2], translation.mData[3]); //scaling = FbxVector4 (scaling.mData[0], scaling.mData[1], scaling.mData[2], scaling.mData[3]); //lVertexTransformMatrix = FbxAMatrix(translation, rotation, scaling); //lVertexTransformMatrix = FbxAMatrix(translation, rotation, scaling); identityM = lVertexTransformMatrix * identityM; D3DXMATRIX convert = D3DXMATRIX(1,0,0,0, 0,0,1,0, 0,1,0,0, 0,0,0,1); D3DXMATRIX setMatrix = D3DXMATRIX( (float)identityM.mData[0].mData[0], (float)identityM.mData[1].mData[0], (float)identityM.mData[2].mData[0], (float)identityM.mData[3].mData[0], (float)identityM.mData[0].mData[1], (float)identityM.mData[1].mData[1], (float)identityM.mData[2].mData[1], (float)identityM.mData[3].mData[1], (float)identityM.mData[0].mData[2], (float)identityM.mData[1].mData[2], (float)identityM.mData[2].mData[2], (float)identityM.mData[3].mData[2], (float)identityM.mData[0].mData[3], (float)identityM.mData[1].mData[3], (float)identityM.mData[2].mData[3],1); //setMatrix *=0.5f; setMatrix = D3DXMATRIX( (float)identityM.mData[0].mData[0], (float)identityM.mData[1].mData[0], (float)identityM.mData[2].mData[0], (float)identityM.mData[3].mData[0], (float)identityM.mData[0].mData[1], (float)identityM.mData[1].mData[1], (float)identityM.mData[2].mData[1], (float)identityM.mData[3].mData[1], //(float)identityM.mData[0].mData[2], (float)identityM.mData[1].mData[2], (float)identityM.mData[2].mData[2], (float)identityM.mData[3].mData[1], (float)identityM.mData[0].mData[2], (float)identityM.mData[1].mData[2], (float)identityM.mData[2].mData[2], (float)identityM.mData[3].mData[2], (float)identityM.mData[0].mData[3], (float)identityM.mData[1].mData[3], (float)identityM.mData[2].mData[3], 1); //setMatrix = setMatrix*convert; ///////// juz prawie dziala. sprawdz jeszcze te addytywne itp. /// generalnie dodaj to do włosów i dorzuć poprzednią macierz, żeby liczyć przesunięcia. //setMatrix /= 2.54f; //skala jedna jest w cm, druga w inchach, nieważne czy zmieniam system skali ręcznie... bzdurka fbxa std::string nametype = lCluster->GetLink()->GetName(); animationStructure->GetSkeleton(frame)->GetBone(animationStructure->GetSkeleton(frame)->GetBoneByName(lCluster->GetLink()->GetName()))->SetTransformation(setMatrix); }//lClusterCount } delete [] lClusterDeformation; delete [] lClusterWeight; }
//Compute the transform matrix that the cluster will transform the vertex. void compute_cluster_deformation(FbxAMatrix& pGlobalPosition, FbxMesh* pMesh, FbxCluster* pCluster, FbxAMatrix& pVertexTransformMatrix, FbxTime pTime, FbxPose* pPose) { FbxCluster::ELinkMode lClusterMode = pCluster->GetLinkMode(); FbxAMatrix lReferenceGlobalInitPosition; FbxAMatrix lReferenceGlobalCurrentPosition; FbxAMatrix lAssociateGlobalInitPosition; FbxAMatrix lAssociateGlobalCurrentPosition; FbxAMatrix lClusterGlobalInitPosition; FbxAMatrix lClusterGlobalCurrentPosition; FbxAMatrix lReferenceGeometry; FbxAMatrix lAssociateGeometry; FbxAMatrix lClusterGeometry; FbxAMatrix lClusterRelativeInitPosition; FbxAMatrix lClusterRelativeCurrentPositionInverse; if(lClusterMode == FbxCluster::eAdditive && pCluster->GetAssociateModel()) { pCluster->GetTransformAssociateModelMatrix(lAssociateGlobalInitPosition); // Geometric transform of the model lAssociateGeometry = get_geometry(pCluster->GetAssociateModel()); lAssociateGlobalInitPosition *= lAssociateGeometry; lAssociateGlobalCurrentPosition = get_global_position(pCluster->GetAssociateModel(), pTime, pPose); pCluster->GetTransformMatrix(lReferenceGlobalInitPosition); // Multiply lReferenceGlobalInitPosition by Geometric Transformation lReferenceGeometry = get_geometry(pMesh->GetNode()); lReferenceGlobalInitPosition *= lReferenceGeometry; lReferenceGlobalCurrentPosition = pGlobalPosition; // Get the link initial global position and the link current global position. pCluster->GetTransformLinkMatrix(lClusterGlobalInitPosition); // Multiply lClusterGlobalInitPosition by Geometric Transformation lClusterGeometry = get_geometry(pCluster->GetLink()); lClusterGlobalInitPosition *= lClusterGeometry; lClusterGlobalCurrentPosition = get_global_position(pCluster->GetLink(), pTime, pPose); // Compute the shift of the link relative to the reference. //ModelM-1 * AssoM * AssoGX-1 * LinkGX * LinkM-1*ModelM pVertexTransformMatrix = lReferenceGlobalInitPosition.Inverse() * lAssociateGlobalInitPosition * lAssociateGlobalCurrentPosition.Inverse() * lClusterGlobalCurrentPosition * lClusterGlobalInitPosition.Inverse() * lReferenceGlobalInitPosition; } else { pCluster->GetTransformMatrix(lReferenceGlobalInitPosition); lReferenceGlobalCurrentPosition = pGlobalPosition; // Multiply lReferenceGlobalInitPosition by Geometric Transformation lReferenceGeometry = get_geometry(pMesh->GetNode()); lReferenceGlobalInitPosition *= lReferenceGeometry; // Get the link initial global position and the link current global position. pCluster->GetTransformLinkMatrix(lClusterGlobalInitPosition); lClusterGlobalCurrentPosition = get_global_position(pCluster->GetLink(), pTime, pPose); // Compute the initial position of the link relative to the reference. lClusterRelativeInitPosition = lClusterGlobalInitPosition.Inverse() * lReferenceGlobalInitPosition; // Compute the current position of the link relative to the reference. lClusterRelativeCurrentPositionInverse = lReferenceGlobalCurrentPosition.Inverse() * lClusterGlobalCurrentPosition; // Compute the shift of the link relative to the reference. pVertexTransformMatrix = lClusterRelativeCurrentPositionInverse * lClusterRelativeInitPosition; } }
// Deform the vertex array in Dual Quaternion Skinning way. void compute_dual_quaternion_deformation(FbxAMatrix& pGlobalPosition, FbxMesh* pMesh, FbxTime& pTime, FbxVector4* pVertexArray, FbxPose* pPose) { // All the links must have the same link mode. FbxCluster::ELinkMode lClusterMode = ((FbxSkin*)pMesh->GetDeformer(0, FbxDeformer::eSkin))->GetCluster(0)->GetLinkMode(); int lVertexCount = pMesh->GetControlPointsCount(); int lSkinCount = pMesh->GetDeformerCount(FbxDeformer::eSkin); FbxDualQuaternion* lDQClusterDeformation = new FbxDualQuaternion[lVertexCount]; memset(lDQClusterDeformation, 0, lVertexCount * sizeof(FbxDualQuaternion)); double* lClusterWeight = new double[lVertexCount]; memset(lClusterWeight, 0, lVertexCount * sizeof(double)); // For all skins and all clusters, accumulate their deformation and weight // on each vertices and store them in lClusterDeformation and lClusterWeight. for(int lSkinIndex=0; lSkinIndex<lSkinCount; ++lSkinIndex) { FbxSkin * lSkinDeformer = (FbxSkin *)pMesh->GetDeformer(lSkinIndex, FbxDeformer::eSkin); int lClusterCount = lSkinDeformer->GetClusterCount(); for(int lClusterIndex=0; lClusterIndex<lClusterCount; ++lClusterIndex) { FbxCluster* lCluster = lSkinDeformer->GetCluster(lClusterIndex); if(!lCluster->GetLink()) { continue; } FbxAMatrix lVertexTransformMatrix; compute_cluster_deformation(pGlobalPosition, pMesh, lCluster, lVertexTransformMatrix, pTime, pPose); FbxQuaternion lQ = lVertexTransformMatrix.GetQ(); FbxVector4 lT = lVertexTransformMatrix.GetT(); FbxDualQuaternion lDualQuaternion(lQ, lT); int lVertexIndexCount = lCluster->GetControlPointIndicesCount(); for(int k = 0; k < lVertexIndexCount; ++k) { int lIndex = lCluster->GetControlPointIndices()[k]; // Sometimes, the mesh can have less points than at the time of the skinning // because a smooth operator was active when skinning but has been deactivated during export. if(lIndex >= lVertexCount) { continue; } double lWeight = lCluster->GetControlPointWeights()[k]; if(lWeight == 0.0) { continue; } // Compute the influence of the link on the vertex. FbxDualQuaternion lInfluence = lDualQuaternion * lWeight; if(lClusterMode == FbxCluster::eAdditive) { // Simply influenced by the dual quaternion. lDQClusterDeformation[lIndex] = lInfluence; // Set the link to 1.0 just to know this vertex is influenced by a link. lClusterWeight[lIndex] = 1.0; } else { // lLinkMode == FbxCluster::eNormalize || lLinkMode == FbxCluster::eTotalOne if(lClusterIndex == 0) { lDQClusterDeformation[lIndex] = lInfluence; } else { // Add to the sum of the deformations on the vertex. // Make sure the deformation is accumulated in the same rotation direction. // Use dot product to judge the sign. double lSign = lDQClusterDeformation[lIndex].GetFirstQuaternion().DotProduct(lDualQuaternion.GetFirstQuaternion()); if(lSign >= 0.0) { lDQClusterDeformation[lIndex] += lInfluence; } else { lDQClusterDeformation[lIndex] -= lInfluence; } } // Add to the sum of weights to either normalize or complete the vertex. lClusterWeight[lIndex] += lWeight; } }//For each vertex }//lClusterCount } //Actually deform each vertices here by information stored in lClusterDeformation and lClusterWeight for(int i = 0; i < lVertexCount; i++) { FbxVector4 lSrcVertex = pVertexArray[i]; FbxVector4& lDstVertex = pVertexArray[i]; double lWeightSum = lClusterWeight[i]; // Deform the vertex if there was at least a link with an influence on the vertex, if(lWeightSum != 0.0) { lDQClusterDeformation[i].Normalize(); lDstVertex = lDQClusterDeformation[i].Deform(lDstVertex); if(lClusterMode == FbxCluster::eNormalize) { // In the normalized link mode, a vertex is always totally influenced by the links. lDstVertex /= lWeightSum; } else if(lClusterMode == FbxCluster::eTotalOne) { // In the total 1 link mode, a vertex can be partially influenced by the links. lSrcVertex *= (1.0 - lWeightSum); lDstVertex += lSrcVertex; } } } delete [] lDQClusterDeformation; delete [] lClusterWeight; }
void MeshImporter::LoadWeight(FbxMesh* fbxMesh, MeshEntry* mesh) { int numSkin = fbxMesh->GetDeformerCount(FbxDeformer::eSkin); if (numSkin == 0) { return; } assert(numSkin == 1); // Assume only one deformer FbxSkin* fbxSkin = static_cast<FbxSkin*>(fbxMesh->GetDeformer(0, FbxDeformer::eSkin)); int numCluster = fbxSkin->GetClusterCount(); int numControlPoints = fbxMesh->GetControlPointsCount(); vector<VertexWeight> tmpWeightList(numControlPoints); for (int i = 0; i < numCluster; i++) { FbxCluster* fbxCluster = fbxSkin->GetCluster(i); if (!fbxCluster->GetLink()) { continue; } unsigned int boneIndex = model->skeleton->bones.size(); assert(fbxCluster->GetLinkMode() == FbxCluster::eNormalize); // Read skeleton bones data (transformation matrix of each bone) string boneName(fbxCluster->GetLink()->GetName()); if (!model->skeleton->FindBoneByName(boneName)) { if (boneIndex >= MAXBONE) { PrintTab("Too many bones to load!!"); } else { // Read weights of each vertex int numIndexInCluster = fbxCluster->GetControlPointIndicesCount(); int* indicesInCluster = fbxCluster->GetControlPointIndices(); double* weights = fbxCluster->GetControlPointWeights(); for (int j = 0; j < numIndexInCluster; j++) { tmpWeightList[indicesInCluster[j]].AddBoneData(boneIndex, weights[j]); } // Normalize weights /*for (int inVert = 0; inVert < tmpWeightList.size(); inVert++) { tmpWeightList[inVert].Normalize(); }*/ // Read animation bone matrix FbxAMatrix fbxGlobalBoneBaseMatrix;// = fbxCluster->GetLink()->EvaluateGlobalTransform().Inverse().Transpose(); FbxAMatrix referenceGlobalInitPosition; FbxAMatrix clusterGlobalInitPosition; fbxCluster->GetTransformMatrix(referenceGlobalInitPosition); fbxCluster->GetTransformLinkMatrix(clusterGlobalInitPosition); fbxGlobalBoneBaseMatrix = clusterGlobalInitPosition.Inverse() * referenceGlobalInitPosition; // To be considered when importing Maya fbx model //FbxAMatrix geoMatrix = GetTransformMatrix(fbxCluster->GetLink()); Bone bone; bone.name = boneName; bone.boneIndex = boneIndex; bone.fbxNode = fbxCluster->GetLink(); bone.globalBindposeInverseMatrix = fbxGlobalBoneBaseMatrix; model->skeleton->bones.push_back(bone); } } } // Deployed in the index for (unsigned int i = 0; i < mesh->numVertices; i++) { mesh->vertices[i].boneIndices.x = tmpWeightList[mesh->indices[i]].boneWeight[0].first; mesh->vertices[i].boneIndices.y = tmpWeightList[mesh->indices[i]].boneWeight[1].first; mesh->vertices[i].boneIndices.z = tmpWeightList[mesh->indices[i]].boneWeight[2].first; mesh->vertices[i].boneIndices.w = tmpWeightList[mesh->indices[i]].boneWeight[3].first; mesh->vertices[i].weights.x = tmpWeightList[mesh->indices[i]].boneWeight[0].second; mesh->vertices[i].weights.y = tmpWeightList[mesh->indices[i]].boneWeight[1].second; mesh->vertices[i].weights.z = tmpWeightList[mesh->indices[i]].boneWeight[2].second; mesh->vertices[i].weights.w = tmpWeightList[mesh->indices[i]].boneWeight[3].second; } }
//FbxAMatrix ComputeTotalMatrix(FbxNode* node, FbxTime time = FBXSDK_TIME_INFINITE){ // //} SkinInfo::SkinInfo(FbxNode* meshNode) : _node(meshNode), _mesh(meshNode->GetMesh()), _skin(nullptr) { int deformerCount = _mesh->GetDeformerCount(); for (auto ix = 0; ix < deformerCount; ++ix){ auto skin = reinterpret_cast<FbxSkin*>(_mesh->GetDeformer(ix, FbxDeformer::eSkin)); if (skin){ _skin = skin; break; } } if (!_skin){ return; } std::vector<FbxPose*> bindPoses; auto poseCount = _node->GetScene()->GetPoseCount(); for (auto ix = 0; ix < poseCount; ++ix){ auto pose = _node->GetScene()->GetPose(ix); if (pose->IsBindPose()){ bindPoses.push_back(pose); } } std::vector<FbxNode*> unsortedFlatListOfNodes; std::vector<FbxCluster*> unsortedFlatListOfClusters; auto clusterCount = _skin->GetClusterCount(); for (auto ix = 0; ix < clusterCount; ++ix){ auto cluster = _skin->GetCluster(ix); if (!cluster) { std::cout << "Invalid skin" << std::endl; _skin = nullptr; return; } auto linkNode = cluster->GetLink(); if (!linkNode){ std::cout << "Invalid skin" << std::endl; _skin = nullptr; return; } unsortedFlatListOfClusters.push_back(cluster); unsortedFlatListOfNodes.push_back(linkNode); } ComputeBoneHierarchy(unsortedFlatListOfNodes, unsortedFlatListOfClusters, _bones, _fbxClusterIndexToBoneIndex, _controlPointToBoneIndicesAndWeights); auto deformType = _skin->GetDeformerType(); auto geometryTransform = GetGeometryTransformation(meshNode); // compute all bones global inverse and global matrix for (auto& bone : _bones){ FbxAMatrix transformMatrix; FbxAMatrix transformLinkMatrix; FbxMatrix globalBindposeInverseMatrix; bone.cluster->GetTransformMatrix(transformMatrix); // The transformation of the mesh at binding time bone.cluster->GetTransformLinkMatrix(transformLinkMatrix); // The transformation of the cluster(joint) at binding time from joint space to world space /*for (auto pose : bindPoses){ auto inPoseIndex = pose->Find(bone.linkNode); if (inPoseIndex >= 0){ auto tempMat = pose->GetMatrix(inPoseIndex); transformLinkMatrix = *(FbxAMatrix*) (double*) &tempMat; break; } }*/ globalBindposeInverseMatrix = FbxMatrix(transformLinkMatrix.Inverse()) * FbxMatrix(transformMatrix) * geometryTransform; bone.matrixGlobalBindPose = ConvertToBabylonCoordinateSystem(globalBindposeInverseMatrix.Inverse()); if (bone.parentBoneIndex == -1){ bone.matrixLocalBindPose = bone.matrixGlobalBindPose; } else{ bone.matrixLocalBindPose = _bones[bone.parentBoneIndex].matrixGlobalBindPose.Inverse()* bone.matrixGlobalBindPose; } } // compute anim auto animStack = _node->GetScene()->GetCurrentAnimationStack(); FbxString animStackName = animStack->GetName(); //FbxTakeInfo* takeInfo = node->GetScene()->GetTakeInfo(animStackName); auto animTimeMode = GlobalSettings::Current().AnimationsTimeMode; auto animFrameRate = GlobalSettings::Current().AnimationsFrameRate(); auto startFrame = animStack->GetLocalTimeSpan().GetStart().GetFrameCount(animTimeMode); auto endFrame = animStack->GetLocalTimeSpan().GetStop().GetFrameCount(animTimeMode); auto animLengthInFrame = endFrame - startFrame + 1; for (auto ix = 0; ix < animLengthInFrame; ix++){ FbxTime currTime; currTime.SetFrame(startFrame + ix, animTimeMode); auto currTransformOffset = FbxMatrix(meshNode->EvaluateGlobalTransform(currTime)) * geometryTransform; auto currTransformOffsetInverse = currTransformOffset.Inverse(); // compute global transform and local for (auto& bone : _bones){ BoneAnimKeyFrame kf; kf.frame = ix; kf.matrixGlobal = ConvertToBabylonCoordinateSystem(currTransformOffsetInverse*bone.linkNode->EvaluateGlobalTransform(currTime)); if (bone.parentBoneIndex == -1){ kf.matrixLocal = kf.matrixGlobal; } else{ auto& parentBone = _bones[bone.parentBoneIndex]; kf.matrixLocal = //bone.matrixLocalBindPose; parentBone.keyFrames[parentBone.keyFrames.size() - 1].matrixGlobal.Inverse()* kf.matrixGlobal; } bone.keyFrames.push_back(kf); } } }
MeshData* FBXImporter::GetMeshInfo() { mMeshData = new MeshData(); int indicesIndexOffset = 0; // 记录当前mesh在整个ib中的索引位移。 int verticesIndexOffset = 0; // 记录当前mesh在整个vb中的顶点位移。 for (int meshIndex = 0; meshIndex < mFBXMeshDatas.size(); meshIndex++) { FbxMesh* mesh = mFBXMeshDatas[meshIndex]->mMesh; FBXMeshData* fbxMeshData = mFBXMeshDatas[meshIndex]; fbxMeshData->mVerticesCount = mesh->GetControlPointsCount(); fbxMeshData->mIndicesCount = mesh->GetPolygonVertexCount(); fbxMeshData->mTrianglesCount = mesh->GetPolygonCount(); // 获取3dsmax中的全局变换矩阵,稍后可以在DX中还原。 FbxMatrix gloableTransform = mesh->GetNode()->EvaluateGlobalTransform(); FbxAMatrix matrixGeo; matrixGeo.SetIdentity(); const FbxVector4 lT = mesh->GetNode()->GetGeometricTranslation(FbxNode::eSourcePivot); const FbxVector4 lR = mesh->GetNode()->GetGeometricRotation(FbxNode::eSourcePivot); const FbxVector4 lS = mesh->GetNode()->GetGeometricScaling(FbxNode::eSourcePivot); matrixGeo.SetT(lT); matrixGeo.SetR(lR); matrixGeo.SetS(lS); FbxAMatrix matrixL2W; matrixL2W.SetIdentity(); matrixL2W = mesh->GetNode()->EvaluateGlobalTransform(); matrixL2W *= matrixGeo; XMMATRIX globalTransform = XMLoadFloat4x4(&fbxMeshData->globalTransform); FbxMatrixToXMMATRIX(globalTransform, matrixL2W); XMStoreFloat4x4(&fbxMeshData->globalTransform, globalTransform); // 读取顶点。 ReadVertices(fbxMeshData); // 读取索引。 ReadIndices(fbxMeshData); // 先读取网格对应的材质索引信息,以便优化稍后纹理读取。 // 一个网格可能只对应一个materialId,也可能对应多个materialId(3dsmax里的Multi/Sub-Object材质)。 // 如果只对应一个材质,简单的读取就行,不过普遍情况可能是为了优化渲染合并mesh从而拥有多材质。 // 这个函数调用完毕我们会得到materialId和拥有这个materialId的三角形列表(三角形编号列表),保存在vector<MaterialIdOffset>的容器中。 //struct Material //{ // Material() {} // Material(int id, string diffuse, string normalMap) // : materialId(id), // diffuseTextureFile(diffuse), // normalMapTextureFile(normalMap) // {} // // int materialId; // string diffuseTextureFile; // string normalMapTextureFile; //}; // struct MaterialIdOffset //{ // MaterialIdOffset() // : polygonCount(0) // {} // int polygonCount; // Material material; //}; ConnectMaterialsToMesh(mesh, fbxMeshData->mTrianglesCount); // 根据ConnectMaterialsToMesh得到的信息读取材质纹理信息,同样存入vector<MaterialIdOffset>容器。 LoadMaterials(fbxMeshData); int triangleCount = mesh->GetPolygonCount(); int controlPointIndex = 0; int normalIndex = 0; fbxMeshData->mUVs.resize(fbxMeshData->mIndicesCount, XMFLOAT2(-1.0f, -1.0f)); // Extract normals and uvs from FbxMesh. for (int i = 0; i < triangleCount; i++) { int polygonSize = mesh->GetPolygonSize(i); for (int j = 0; j < polygonSize; j++) { controlPointIndex = mesh->GetPolygonVertex(i, j); ReadNormals(fbxMeshData, controlPointIndex, normalIndex); // 有纹理我们才读取uv,tangent以及binormal。 if (fbxMeshData->hasDiffuseTexture()) { ReadUVs(fbxMeshData, controlPointIndex, normalIndex, mesh->GetTextureUVIndex(i, j), 0); ReadTangents(fbxMeshData, controlPointIndex, normalIndex); ReadBinormals(fbxMeshData, controlPointIndex, normalIndex); } normalIndex++; } } SplitVertexByNormal(fbxMeshData); if (fbxMeshData->hasDiffuseTexture()) { SplitVertexByUV(fbxMeshData); } else { fbxMeshData->mUVs.resize(fbxMeshData->mVerticesCount); } if (fbxMeshData->hasNormalMapTexture()) { SplitVertexByTangent(fbxMeshData); SplitVertexByBinormal(fbxMeshData); } else { fbxMeshData->mTangents.resize(fbxMeshData->mVerticesCount); fbxMeshData->mBinormals.resize(fbxMeshData->mVerticesCount); } // 如果.fbx包含一个以上的mesh,需要计算当前FBXMeshData的索引在全局索引中的位置。 for (int i = 0; i < fbxMeshData->mIndicesCount; i++) { fbxMeshData->mIndices[i] = fbxMeshData->mIndices[i] + verticesIndexOffset; } mMeshData->verticesCount += fbxMeshData->mVerticesCount; mMeshData->indicesCount += fbxMeshData->mIndicesCount; mMeshData->meshesCount++; // 多材质的情况。 // 根据之前填充的materialIdOffsets容器保存的materialId和三角形的对应关系, // 计算每个RenderPackage渲染所需的索引数量和索引起始位置(偏移)。 if (isByPolygon && fbxMeshData->hasDiffuseTexture()) { vector<MaterialIdOffset> materialIdOffsets = mMeshData->materialIdOffsets; for (int i = 0; i < materialIdOffsets.size(); i++) { RenderPackage renderPacakge; renderPacakge.globalTransform = fbxMeshData->globalTransform; renderPacakge.indicesCount = materialIdOffsets[i].polygonCount * 3; if (i == 0) { renderPacakge.indicesOffset = indicesIndexOffset; } else { renderPacakge.indicesOffset += indicesIndexOffset; } renderPacakge.material = materialIdOffsets[i].material; mMeshData->renderPackages.push_back(renderPacakge); indicesIndexOffset += renderPacakge.indicesCount; } } else // 单一材质的情况。 { RenderPackage renderPackage; renderPackage.indicesCount = fbxMeshData->mIndicesCount; renderPackage.indicesOffset = indicesIndexOffset; renderPackage.material = fbxMeshData->mMaterial; renderPackage.globalTransform = fbxMeshData->globalTransform; mMeshData->renderPackages.push_back(renderPackage); indicesIndexOffset += fbxMeshData->mIndices.size(); } verticesIndexOffset += fbxMeshData->mVertices.size(); // 将当前mesh的数据追加到全局数据容器。 Merge(mMeshData->vertices, fbxMeshData->mVertices); Merge(mMeshData->indices, fbxMeshData->mIndices); Merge(mMeshData->normals, fbxMeshData->mNormals); Merge(mMeshData->uvs, fbxMeshData->mUVs); Merge(mMeshData->tangents, fbxMeshData->mTangents); Merge(mMeshData->binormals, fbxMeshData->mBinormals); mMeshData->materialIdOffsets.clear(); } clear(); return mMeshData; }
void FbxLoader::ProcessBoneAndAnimation(FbxNode* node, Node& meshNode) { auto currMesh = node->GetMesh(); if(!currMesh) return; FbxVector4 lT = node->GetGeometricTranslation(FbxNode::eSourcePivot); FbxVector4 lR = node->GetGeometricRotation(FbxNode::eSourcePivot); FbxVector4 lS = node->GetGeometricScaling(FbxNode::eSourcePivot); FbxAMatrix geometryTransform = FbxAMatrix(lT, lR, lS); FbxSkin* skin = nullptr; const int deformerCnt = currMesh->GetDeformerCount(); for(int deformerIndex = 0; deformerIndex < deformerCnt; ++deformerIndex) { skin = (FbxSkin*)(currMesh->GetDeformer(deformerIndex, FbxDeformer::eSkin)); if(skin) break; } if(!skin) return; meshNode.useSkinnedMesh = true; const size_t nClusters = skin->GetClusterCount(); if(nClusters < 1) return; for(auto& clip : animationClips) clip.second->transformCurves.resize(nClusters); meshNode.bones.resize(nClusters); const int animCount = scene->GetSrcObjectCount<FbxAnimStack>(); float time = 0; for(int ci = 0; ci < nClusters; ++ci) { FbxCluster* cluster = skin->GetCluster(ci); auto elink = cluster->GetLinkMode(); std::string boneName = cluster->GetLink()->GetName(); FbxAMatrix transformMatrix, transformLinkMatrix, globalBindposeInverse; cluster->GetTransformMatrix(transformMatrix); cluster->GetTransformLinkMatrix(transformLinkMatrix); globalBindposeInverse = transformLinkMatrix.Inverse() * geometryTransform * transformMatrix; FbxNode* boneNode = cluster->GetLink(); Bone& bone = meshNode.bones[ci]; bone.name = boneName; bone.index = ci; auto T = globalBindposeInverse.GetT() * factor; if(axismode == eLeftHanded) { auto R = globalBindposeInverse.GetR(); T[0] *= -1; R[1] *= -1; R[2] *= -1; globalBindposeInverse.SetR(R); } globalBindposeInverse.SetT(T); ConvertMatrix(bone.bindPoseInverse, globalBindposeInverse); const int nCtrl = cluster->GetControlPointIndicesCount(); for(int ctrlIndex = 0; ctrlIndex < nCtrl; ++ctrlIndex) { BlendWeightPair pair; pair.boneIndex = ci; pair.weight = (float)cluster->GetControlPointWeights()[ctrlIndex]; meshNode.controlPoints[cluster->GetControlPointIndices()[ctrlIndex]].blendWeigths.push_back(pair); } FbxAMatrix preRot; auto preR = boneNode->GetPreRotation(FbxNode::eSourcePivot); preRot.SetR(preR); for(int ai = 0; ai < animCount; ++ai) { auto animStack = scene->GetSrcObject<FbxAnimStack>(ai); scene->SetCurrentAnimationStack(animStack); std::string animName = animStack->GetName(); auto& clip = animationClips[animName]; auto& transformCurve = clip->transformCurves[ci]; transformCurve.boneName = boneName; transformCurve.begin = 0; auto animLayer = animStack->GetMember<FbxAnimLayer>(0); FbxAnimCurve* fbxTCurves[3]; FbxAnimCurve* fbxRCurves[3]; FbxAnimCurve* fbxSCurves[3]; fbxTCurves[0] = boneNode->LclTranslation.GetCurve(animLayer, "X"); if(!fbxTCurves[0]) continue; fbxTCurves[1] = boneNode->LclTranslation.GetCurve(animLayer, "Y"); fbxTCurves[2] = boneNode->LclTranslation.GetCurve(animLayer, "Z"); fbxRCurves[0] = boneNode->LclRotation.GetCurve(animLayer, "X"); fbxRCurves[1] = boneNode->LclRotation.GetCurve(animLayer, "Y"); fbxRCurves[2] = boneNode->LclRotation.GetCurve(animLayer, "Z"); fbxSCurves[0] = boneNode->LclScaling.GetCurve(animLayer, "X"); fbxSCurves[1] = boneNode->LclScaling.GetCurve(animLayer, "Y"); fbxSCurves[2] = boneNode->LclScaling.GetCurve(animLayer, "Z"); // set & apply filter FbxAnimCurveFilterKeyReducer keyReducer; keyReducer.SetKeySync(false); keyReducer.Apply(fbxTCurves, 3); keyReducer.Apply(fbxSCurves, 3); keyReducer.SetKeySync(true); keyReducer.Apply(fbxRCurves, 3); FbxAnimCurveFilterUnroll unroll; unroll.SetForceAutoTangents(true); unroll.Apply(fbxRCurves, 3); FbxAnimCurveFilterTSS tss; FbxTime tt; tt.SetSecondDouble(-fbxTCurves[0]->KeyGetTime(0).GetSecondDouble()); tss.SetShift(tt); tss.Apply(fbxTCurves, 3); tss.Apply(fbxRCurves, 3); tss.Apply(fbxSCurves, 3); // // process curves if(fbxTCurves[0]->KeyGetCount() > 0) { ProcessAnimCurveT(fbxTCurves, transformCurve); ProcessAnimCurveS(fbxSCurves, transformCurve); ProcessAnimCurveR(fbxRCurves, transformCurve, preRot); //clamping by reduced keyframes clip->startTime = 0; clip->lengthInSeconds = transformCurve.end; clip->lengthInFrames = (int)(1.5f + (transformCurve.end / (1 / 30.0f))); } } // animations loop } // cluster loop }
void FBXSceneEncoder::transformNode(FbxNode* fbxNode, Node* node) { FbxAMatrix matrix; float m[16]; if (fbxNode->GetCamera() || fbxNode->GetLight()) { FbxAMatrix rotateAdjust; if(fbxNode->GetLight()) { /* * according to the fbx-documentation the light's forward vector * points along a node's negative Y axis. * so we have to rotate it by 90° around the X-axis to correct it. */ if(fbxNode->RotationActive.Get()) { const FbxVector4& postRotation = fbxNode->PostRotation.Get(); fbxNode->SetPostRotation(FbxNode::eSourcePivot, FbxVector4(postRotation.mData[0] + 90.0, postRotation.mData[1], postRotation.mData[2]) ); } else { // if the rotation is deactivated we have to rotate it anyway to get the correct transformation in the end rotateAdjust.SetR(FbxVector4(-90.0, 0.0, 0.0)); } matrix = fbxNode->EvaluateLocalTransform() * rotateAdjust; } else if(fbxNode->GetCamera()) { /* * according to the fbx-documentation the camera's forward vector * points along a node's positive X axis. * so we have to rotate it by 90 around the Y-axis to correct it. */ if (fbxNode->RotationActive.Get()) { const FbxVector4& postRotation = fbxNode->PostRotation.Get(); fbxNode->SetPostRotation(FbxNode::eSourcePivot, FbxVector4(postRotation.mData[0], postRotation.mData[1] + 90.0, postRotation.mData[2])); } else { // usually for the fbx-exporter in Blender 2.75 // if rotation is deactivated we have to rotate the local transform in 90° rotateAdjust.SetR(FbxVector4(0, 90.0, 0.0)); } matrix = fbxNode->EvaluateLocalTransform() * rotateAdjust; } copyMatrix(matrix, m); node->setTransformMatrix(m); } else { matrix = fbxNode->EvaluateLocalTransform(); copyMatrix(matrix, m); node->setTransformMatrix(m); } }
bool Submesh::load(FbxNode* pNode, FbxMesh* pMesh, const std::vector<face>& faces, const std::vector<vertexInfo>& vertInfo, const std::vector<FbxVector4>& points, const std::vector<FbxVector4>& normals, const std::vector<int>& texcoordsets, ParamList& params, const FbxAMatrix& bindPose, bool opposite ) { //save the mesh from which this submesh will be created m_pNode = pNode; size_t i,j,k; FxOgreFBXLog( "Loading submesh associated to material: %s ...\n", m_pMaterial->name().c_str()); //save uvsets info for (i=m_uvsets.size(); i<texcoordsets.size(); i++) { uvset uv; uv.size = 2; m_uvsets.push_back(uv); } //iterate over faces array, to retrieve vertices info for (i=0; i<faces.size(); i++) { face newFace; // if we are using shared geometry, indexes refer to the vertex buffer of the whole mesh if (params.useSharedGeom) { if(opposite) { // reverse order of face vertices for correct culling newFace.v[0] = faces[i].v[2]; newFace.v[1] = faces[i].v[1]; newFace.v[2] = faces[i].v[0]; } else { newFace.v[0] = faces[i].v[0]; newFace.v[1] = faces[i].v[1]; newFace.v[2] = faces[i].v[2]; } } // otherwise we create a vertex buffer for this submesh else { // faces are triangles, so retrieve index of the three vertices for (j=0; j<3; j++) { vertex v; vertexInfo vInfo = vertInfo[faces[i].v[j]]; // save vertex coordinates (rescale to desired length unit) assert(vInfo.pointIdx >= 0 && vInfo.pointIdx < static_cast<int>(points.size())); FbxVector4 point = points[vInfo.pointIdx] * params.lum; if (fabs(point[0]) < PRECISION) point[0] = 0; if (fabs(point[1]) < PRECISION) point[1] = 0; if (fabs(point[2]) < PRECISION) point[2] = 0; v.x = point[0]; v.y = point[1]; v.z = point[2]; // save vertex normal assert(vInfo.normalIdx >= 0 && vInfo.normalIdx < static_cast<int>(normals.size())); FbxVector4 normal = normals[vInfo.normalIdx]; if (fabs(normal[0]) < PRECISION) normal[0] = 0; if (fabs(normal[1]) < PRECISION) normal[1] = 0; if (fabs(normal[2]) < PRECISION) normal[2] = 0; v.n.x = normal[0]; v.n.y = normal[1]; v.n.z = normal[2]; if (opposite) { // Reversing the winding order appears to be sufficent. v.n.x = -normal[0]; v.n.y = -normal[1]; v.n.z = -normal[2]; } v.n.Normalize(); // save vertex color v.r = vInfo.r; v.g = vInfo.g; v.b = vInfo.b; v.a = vInfo.a; // save vertex bone assignements for (k=0; k<vInfo.vba.size(); k++) { vba newVba; newVba.jointIdx = vInfo.jointIds[k]; newVba.weight = vInfo.vba[k]; v.vbas.push_back(newVba); } // save texture coordinates for (k=0; k<vInfo.u.size(); k++) { texcoord newTexCoords; newTexCoords.u = vInfo.u[k]; newTexCoords.v = vInfo.v[k]; newTexCoords.w = 0; v.texcoords.push_back(newTexCoords); } // save vertex index in mesh, to retrieve future positions of the same vertex v.index = vInfo.pointIdx; // add newly created vertex to vertex list m_vertices.push_back(v); if (opposite) // reverse order of face vertices to get correct culling newFace.v[2-j] = static_cast<int>(m_vertices.size()) - 1; else newFace.v[j] = static_cast<int>(m_vertices.size()) - 1; } } m_faces.push_back(newFace); } // set use32bitIndexes flag if (params.useSharedGeom || (m_vertices.size() > 65535) || (m_faces.size() > 65535)) m_use32bitIndexes = true; else m_use32bitIndexes = false; pMesh->ComputeBBox(); FbxDouble3 minDouble = pMesh->BBoxMin.Get(); FbxDouble3 maxDouble = pMesh->BBoxMax.Get(); FbxVector4 min = bindPose.MultT( FbxVector4(minDouble[0],minDouble[1],minDouble[2],0)); FbxVector4 max = bindPose.MultT( FbxVector4(maxDouble[0],maxDouble[1],maxDouble[2],0)); m_bbox.merge(Point3(max[0], max[1], max[2])); m_bbox.merge(Point3(min[0], min[1], min[2])); // add submesh pointer to m_params list params.loadedSubmeshes.push_back(this); FxOgreFBXLog( "DONE\n"); return true; }
//Compute the transform matrix that the cluster will transform the vertex. void ofxFBXMesh::computeClusterDeformation(FbxAMatrix& pGlobalPosition, FbxMesh* pMesh, FbxCluster* pCluster, FbxAMatrix& pVertexTransformMatrix, FbxTime pTime, FbxPose* pPose) { FbxCluster::ELinkMode lClusterMode = pCluster->GetLinkMode(); FbxAMatrix lReferenceGlobalInitPosition; FbxAMatrix lReferenceGlobalCurrentPosition; FbxAMatrix lAssociateGlobalInitPosition; FbxAMatrix lAssociateGlobalCurrentPosition; FbxAMatrix lClusterGlobalInitPosition; FbxAMatrix lClusterGlobalCurrentPosition; FbxAMatrix lReferenceGeometry; FbxAMatrix lAssociateGeometry; FbxAMatrix lClusterGeometry; FbxAMatrix lClusterRelativeInitPosition; FbxAMatrix lClusterRelativeCurrentPositionInverse; ofxFBXBone* bone = NULL; ofxFBXCluster* cluster = NULL; if(pCluster->GetLink()) { FbxNode* boneNode = pCluster->GetLink(); if(boneNode->GetUserDataPtr()) { bone = static_cast<ofxFBXBone *>(boneNode->GetUserDataPtr()); } } if(bone != NULL) { if(pCluster->GetUserDataPtr()) { cluster = static_cast<ofxFBXCluster *>(pCluster->GetUserDataPtr()); // cluster->update( pTime, pPose ); } } if( bone != NULL && cluster != NULL ) { // cout << "We have cached cluster and bone! " << bone->getName() << endl; pVertexTransformMatrix = cluster->preTrans * bone->fbxTransform * cluster->postTrans; } else { // nothing is setup for the control of the bones, so we are just doing animation // right now, can't do animation and control the bones at the same time. if (lClusterMode == FbxCluster::eAdditive && pCluster->GetAssociateModel()) { pCluster->GetTransformAssociateModelMatrix(lAssociateGlobalInitPosition); // Geometric transform of the model lAssociateGeometry = GetGeometry(pCluster->GetAssociateModel()); lAssociateGlobalInitPosition *= lAssociateGeometry; lAssociateGlobalCurrentPosition = GetGlobalPosition(pCluster->GetAssociateModel(), pTime, pPose); pCluster->GetTransformMatrix(lReferenceGlobalInitPosition); // Multiply lReferenceGlobalInitPosition by Geometric Transformation lReferenceGeometry = GetGeometry(pMesh->GetNode()); lReferenceGlobalInitPosition *= lReferenceGeometry; lReferenceGlobalCurrentPosition = pGlobalPosition; // Get the link initial global position and the link current global position. pCluster->GetTransformLinkMatrix(lClusterGlobalInitPosition); // Multiply lClusterGlobalInitPosition by Geometric Transformation lClusterGeometry = GetGeometry(pCluster->GetLink()); lClusterGlobalInitPosition *= lClusterGeometry; lClusterGlobalCurrentPosition = GetGlobalPosition(pCluster->GetLink(), pTime, pPose); // Compute the shift of the link relative to the reference. //ModelM-1 * AssoM * AssoGX-1 * LinkGX * LinkM-1*ModelM pVertexTransformMatrix = lReferenceGlobalInitPosition.Inverse() * lAssociateGlobalInitPosition * lAssociateGlobalCurrentPosition.Inverse() * lClusterGlobalCurrentPosition * lClusterGlobalInitPosition.Inverse() * lReferenceGlobalInitPosition; } else { pCluster->GetTransformMatrix(lReferenceGlobalInitPosition); lReferenceGlobalCurrentPosition = pGlobalPosition; // Multiply lReferenceGlobalInitPosition by Geometric Transformation lReferenceGeometry = GetGeometry(pMesh->GetNode()); lReferenceGlobalInitPosition *= lReferenceGeometry; // Get the link initial global position and the link current global position. pCluster->GetTransformLinkMatrix(lClusterGlobalInitPosition); lClusterGlobalCurrentPosition = GetGlobalPosition(pCluster->GetLink(), pTime, pPose); // Compute the initial position of the link relative to the reference. lClusterRelativeInitPosition = lClusterGlobalInitPosition.Inverse() * lReferenceGlobalInitPosition; // Compute the current position of the link relative to the reference. lClusterRelativeCurrentPositionInverse = lReferenceGlobalCurrentPosition.Inverse() * lClusterGlobalCurrentPosition; // Compute the shift of the link relative to the reference. pVertexTransformMatrix = lClusterRelativeCurrentPositionInverse * lClusterRelativeInitPosition; } } }