src/fbx/FbxSkinningAccess.cpp (80 lines of code) (raw):
/**
* Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "FbxSkinningAccess.hpp"
FbxSkinningAccess::FbxSkinningAccess(const FbxMesh* pMesh, FbxScene* pScene, FbxNode* pNode)
: rootIndex(-1) {
for (int deformerIndex = 0; deformerIndex < pMesh->GetDeformerCount(); deformerIndex++) {
FbxSkin* skin =
reinterpret_cast<FbxSkin*>(pMesh->GetDeformer(deformerIndex, FbxDeformer::eSkin));
if (skin != nullptr) {
const int clusterCount = skin->GetClusterCount();
if (clusterCount == 0) {
continue;
}
int controlPointCount = pMesh->GetControlPointsCount();
vertexJointIndices.resize(controlPointCount, Vec4i(0, 0, 0, 0));
vertexJointWeights.resize(controlPointCount, Vec4f(0.0f, 0.0f, 0.0f, 0.0f));
for (int clusterIndex = 0; clusterIndex < clusterCount; clusterIndex++) {
FbxCluster* cluster = skin->GetCluster(clusterIndex);
const int indexCount = cluster->GetControlPointIndicesCount();
const int* clusterIndices = cluster->GetControlPointIndices();
const double* clusterWeights = cluster->GetControlPointWeights();
assert(
cluster->GetLinkMode() == FbxCluster::eNormalize ||
cluster->GetLinkMode() == FbxCluster::eTotalOne);
// Transform link matrix.
FbxAMatrix transformLinkMatrix;
cluster->GetTransformLinkMatrix(transformLinkMatrix);
// The transformation of the mesh at binding time
FbxAMatrix transformMatrix;
cluster->GetTransformMatrix(transformMatrix);
// Inverse bind matrix.
FbxAMatrix globalBindposeInverseMatrix = transformLinkMatrix.Inverse() * transformMatrix;
inverseBindMatrices.emplace_back(globalBindposeInverseMatrix);
jointNodes.push_back(cluster->GetLink());
jointIds.push_back(cluster->GetLink()->GetUniqueID());
const FbxAMatrix globalNodeTransform = cluster->GetLink()->EvaluateGlobalTransform();
jointSkinningTransforms.push_back(
FbxMatrix(globalNodeTransform * globalBindposeInverseMatrix));
jointInverseGlobalTransforms.push_back(FbxMatrix(globalNodeTransform.Inverse()));
for (int i = 0; i < indexCount; i++) {
if (clusterIndices[i] < 0 || clusterIndices[i] >= controlPointCount) {
continue;
}
if (clusterWeights[i] <= vertexJointWeights[clusterIndices[i]][MAX_WEIGHTS - 1]) {
continue;
}
vertexJointIndices[clusterIndices[i]][MAX_WEIGHTS - 1] = clusterIndex;
vertexJointWeights[clusterIndices[i]][MAX_WEIGHTS - 1] = (float)clusterWeights[i];
for (int j = MAX_WEIGHTS - 1; j > 0; j--) {
if (vertexJointWeights[clusterIndices[i]][j - 1] >=
vertexJointWeights[clusterIndices[i]][j]) {
break;
}
std::swap(
vertexJointIndices[clusterIndices[i]][j - 1],
vertexJointIndices[clusterIndices[i]][j]);
std::swap(
vertexJointWeights[clusterIndices[i]][j - 1],
vertexJointWeights[clusterIndices[i]][j]);
}
}
}
for (int i = 0; i < controlPointCount; i++) {
const float weightSumRcp = 1.0 /
(vertexJointWeights[i][0] + vertexJointWeights[i][1] + vertexJointWeights[i][2] +
vertexJointWeights[i][3]);
vertexJointWeights[i] *= weightSumRcp;
}
}
}
rootIndex = -1;
for (size_t i = 0; i < jointNodes.size() && rootIndex == -1; i++) {
rootIndex = (int)i;
FbxNode* parent = jointNodes[i]->GetParent();
if (parent == nullptr) {
break;
}
for (size_t j = 0; j < jointNodes.size(); j++) {
if (jointNodes[j] == parent) {
rootIndex = -1;
break;
}
}
}
}