Skip to content

Commit

Permalink
build skeleton
Browse files Browse the repository at this point in the history
  • Loading branch information
T-rvw committed Jan 5, 2024
1 parent 324ce29 commit 2c79c89
Show file tree
Hide file tree
Showing 10 changed files with 182 additions and 49 deletions.
152 changes: 119 additions & 33 deletions private/Producers/FbxProducer/FbxProducerImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,29 @@ void FbxProducerImpl::Execute(cd::SceneDatabase* pSceneDatabase)
}
}

if (IsOptionEnabled(FbxProducerOptions::ImportSkeleton))
{
cd::Skeleton skeleton;
skeleton.SetID(m_skeletonIDGenerator.AllocateID());

// Build skeleton bones tree.
TraverseBoneRecursively(pSDKScene->GetRootNode(), cd::BoneID::InvalidID, skeleton, pSceneDatabase);

for (auto& bone : pSceneDatabase->GetBones())
{
if (!bone.GetParentID().IsValid())
{
skeleton.AddRootBoneID(bone.GetID());
}
}

if (skeleton.GetBoneIDCount() > 0U)
{
pSceneDatabase->AddSkeleton(cd::MoveTemp(skeleton));
}
}

// Convert fbx scene nodes/meshes to cd scene nodes/meshes.
assert(pSDKScene->GetRootNode());
TraverseNodeRecursively(pSDKScene->GetRootNode(), cd::NodeID::InvalidID, pSceneDatabase);

if (IsOptionEnabled(FbxProducerOptions::ImportAnimation))
Expand All @@ -253,14 +274,28 @@ void FbxProducerImpl::Execute(cd::SceneDatabase* pSceneDatabase)
}
}

void FbxProducerImpl::TraverseBoneRecursively(fbxsdk::FbxNode* pSDKNode, cd::BoneID parentBoneID, cd::Skeleton& skeleton, cd::SceneDatabase* pSceneDatabase)
{
fbxsdk::FbxNodeAttribute* pNodeAttribute = pSDKNode->GetNodeAttribute();
if (pNodeAttribute != nullptr && FbxNodeAttribute::eSkeleton == pNodeAttribute->GetAttributeType())
{
parentBoneID = ParseBone(pSDKNode, parentBoneID, skeleton, pSceneDatabase);
}

for (int childIndex = 0; childIndex < pSDKNode->GetChildCount(); ++childIndex)
{
TraverseBoneRecursively(pSDKNode->GetChild(childIndex), parentBoneID, skeleton, pSceneDatabase);
}
}

void FbxProducerImpl::TraverseNodeRecursively(fbxsdk::FbxNode* pSDKNode, cd::NodeID parentNodeID, cd::SceneDatabase* pSceneDatabase)
{
fbxsdk::FbxNodeAttribute* pNodeAttribute = pSDKNode->GetNodeAttribute();

if (nullptr == pNodeAttribute ||
fbxsdk::FbxNodeAttribute::eNull == pNodeAttribute->GetAttributeType())
{
ParseNode(pSDKNode, parentNodeID, pSceneDatabase);
parentNodeID = ParseNode(pSDKNode, parentNodeID, pSceneDatabase);
}
else if (fbxsdk::FbxNodeAttribute::eLight == pNodeAttribute->GetAttributeType() && IsOptionEnabled(FbxProducerOptions::ImportLight))
{
Expand Down Expand Up @@ -310,27 +345,29 @@ void FbxProducerImpl::TraverseNodeRecursively(fbxsdk::FbxNode* pSDKNode, cd::Nod
if (IsOptionEnabled(FbxProducerOptions::ImportBlendShape))
{
int32_t blendShapeCount = pFbxMesh->GetDeformerCount(fbxsdk::FbxDeformer::eBlendShape);
mesh.SetBlendShapeIDCount(blendShapeCount);
for (int32_t blendShapeIndex = 0; blendShapeIndex < blendShapeCount; ++blendShapeIndex)
{
const auto* pBlendShape = static_cast<fbxsdk::FbxBlendShape*>(pFbxMesh->GetDeformer(blendShapeIndex, fbxsdk::FbxDeformer::eBlendShape));
mesh.SetBlendShapeID(blendShapeIndex, ParseBlendShape(pBlendShape, mesh, pSceneDatabase));
auto blendShapeID = ParseBlendShape(pBlendShape, mesh, pSceneDatabase);
if (blendShapeID.IsValid())
{
mesh.AddBlendShapeID(blendShapeID);
}
}
}

// SkinMesh
// Skin
if (IsOptionEnabled(FbxProducerOptions::ImportSkinMesh))
{
auto& vertexFormat = mesh.GetVertexFormat();
vertexFormat.AddAttributeLayout(cd::VertexAttributeType::BoneIndex, cd::AttributeValueType::Int16, cd::MaxBoneInfluenceCount);
vertexFormat.AddAttributeLayout(cd::VertexAttributeType::BoneWeight, cd::AttributeValueType::Float, cd::MaxBoneInfluenceCount);

int32_t skinDeformerCount = pFbxMesh->GetDeformerCount(fbxsdk::FbxDeformer::eSkin);
mesh.SetSkinIDCount(skinDeformerCount);
for (int32_t skinIndex = 0; skinIndex < skinDeformerCount; ++skinIndex)
{
const auto* pSkin = static_cast<fbxsdk::FbxSkin*>(pFbxMesh->GetDeformer(skinIndex, fbxsdk::FbxDeformer::eSkin));
mesh.SetSkinID(skinIndex, ParseSkin(pSkin, mesh, pSceneDatabase));
auto skinID = ParseSkin(pSkin, mesh, pSceneDatabase);
if (skinID.IsValid())
{
mesh.AddSkinID(skinID);
}
}
}

Expand Down Expand Up @@ -687,7 +724,6 @@ cd::BlendShapeID FbxProducerImpl::ParseBlendShape(const fbxsdk::FbxBlendShape* p
for (int32_t targetShapeIndex = 0; targetShapeIndex < targetShapeCount; ++targetShapeIndex)
{
const fbxsdk::FbxShape* pTargetShape = pChannel->GetTargetShape(targetShapeIndex);
assert(pTargetShape);

cd::Morph morph;
morph.SetID(m_morphIDGenerator.AllocateID());
Expand Down Expand Up @@ -715,50 +751,77 @@ cd::BlendShapeID FbxProducerImpl::ParseBlendShape(const fbxsdk::FbxBlendShape* p
}
}

pSceneDatabase->AddBlendShape(cd::MoveTemp(blendShape));

return blendShapeID;
if (blendShape.GetMorphIDCount() > 0U)
{
pSceneDatabase->AddBlendShape(cd::MoveTemp(blendShape));
return blendShapeID;
}

return cd::BlendShapeID::InvalidID;
}

cd::SkinID FbxProducerImpl::ParseSkin(const fbxsdk::FbxSkin* pSkin, const cd::Mesh& sourceMesh, cd::SceneDatabase* pSceneDatabase)
{
assert(pSkin);
assert(fbxsdk::FbxSkin::eLinear == pSkin->GetSkinningType() || fbxsdk::FbxSkin::eRigid == pSkin->GetSkinningType());

cd::SkinID skinID = m_skinIDGenerator.AllocateID();
uint32_t influenceBoneCount = pSkin->GetClusterCount();
uint32_t meshVertexCount = sourceMesh.GetVertexPositionCount();

cd::Skin skin;
skin.SetID(skinID);
skin.SetMeshID(sourceMesh.GetID());
skin.SetName(pSkin->GetName());
skin.SetVertexInfluenceBoneIDCount(influenceBoneCount);
skin.SetVertexBoneIndexCount(sourceMesh.GetVertexPositionCount());
skin.SetVertexBoneWeightCount(sourceMesh.GetVertexPositionCount());
skin.SetVertexBoneNameCount(meshVertexCount);
skin.SetVertexBoneWeightCount(meshVertexCount);

for (int32_t skinClusterIndex = 0; skinClusterIndex < pSkin->GetClusterCount(); ++skinClusterIndex)
{
const fbxsdk::FbxCluster* pSkinCluster = pSkin->GetCluster(skinClusterIndex);
assert(pSkinCluster);

const fbxsdk::FbxNode* pLinkBone = pSkinCluster->GetLink();
assert(pLinkBone);
if (!pLinkBone)
{
continue;
}

const char* pBoneName = pLinkBone->GetName();
cd::Bone* pBone = pSceneDatabase->GetBoneByName(pBoneName);
if (!pBone)
{
continue;
}

if (!skin.GetSkeletonID().IsValid())
{
skin.SetSkeletonID(pBone->GetSkeletonID());
}
else
{
assert(skin.GetSkeletonID() == pBone->GetSkeletonID());
}
skin.AddVertexInfluenceBoneName(pBoneName);

const int32_t controlPointIndicesCount = pSkinCluster->GetControlPointIndicesCount();
int* pControlPointIndices = pSkinCluster->GetControlPointIndices();
double* pBoneWeights = pSkinCluster->GetControlPointWeights();
for (int32_t controlPointIndex = 0; controlPointIndex < controlPointIndicesCount; ++controlPointIndex)
{
uint32_t vertexIndex = pControlPointIndices[controlPointIndex];
float boneWeight = static_cast<float>(pBoneWeights[controlPointIndex]);

assert(vertexIndex < meshVertexCount);

auto boneWeight = static_cast<float>(pBoneWeights[controlPointIndex]);
skin.SetVertexBoneName(vertexIndex, pBoneName);
skin.SetVertexBoneWeight(vertexIndex, boneWeight);
}
}

pSceneDatabase->AddSkin(cd::MoveTemp(skin));

return skinID;
if (skin.GetVertexInfluenceBoneNameCount() > 0U)
{
pSceneDatabase->AddSkin(cd::MoveTemp(skin));
}

return cd::SkinID::InvalidID;
}

std::pair<cd::MaterialID, bool> FbxProducerImpl::AllocateMaterialID(const fbxsdk::FbxSurfaceMaterial* pSDKMaterial)
Expand Down Expand Up @@ -864,11 +927,30 @@ cd::MaterialID FbxProducerImpl::ParseMaterial(const fbxsdk::FbxSurfaceMaterial*
return materialID;
}

cd::BoneID FbxProducerImpl::ParseBone(const fbxsdk::FbxNode* pSDKNode, cd::BoneID parentBoneID, cd::SceneDatabase* pSceneDatabase)
cd::BoneID FbxProducerImpl::ParseBone(fbxsdk::FbxNode* pSDKNode, cd::BoneID parentBoneID, cd::Skeleton& skeleton, cd::SceneDatabase* pSceneDatabase)
{
cd::BoneID boneID = m_boneIDGenerator.AllocateID();
cd::Bone bone(boneID, pSDKNode->GetName());
bone.SetTransform(details::ConvertFbxNodeTransform(const_cast<fbxsdk::FbxNode*>(pSDKNode)));
bone.SetSkeletonID(skeleton.GetID());
skeleton.AddBoneID(boneID);

//fbxsdk::FbxAMatrix localTransform = pSDKNode->EvaluateLocalTransform();
//fbxsdk::FbxAMatrix globalTransform = pSDKNode->EvaluateGlobalTransform();
//fbxsdk::FbxAMatrix parentGlobalTransform;
//if (fbxsdk::FbxNode* pParentNode = pSDKNode->GetParent())
//{
// parentGlobalTransform = pParentNode->EvaluateGlobalTransform();
//}
//else
//{
// parentGlobalTransform.SetIdentity();
//}
//
//cd::Transform& boneTransform = bone.GetTransform();
//boneTransform.SetTranslation(globalTransform.GetT() - parentGlobalTransform.GetT());
//boneTransform.SetRotation(localTransform.GetR());
//boneTransform.SetScale(localTransform.GetS());

if (parentBoneID.IsValid())
{
pSceneDatabase->GetBone(parentBoneID.Data()).AddChildID(boneID.Data());
Expand Down Expand Up @@ -968,27 +1050,31 @@ void FbxProducerImpl::ParseAnimation(fbxsdk::FbxScene* scene, cd::SceneDatabase*
boneTrack.SetRotationKeyCount(trackCount);
boneTrack.SetScaleKeyCount(trackCount);
std::vector<cd::Matrix4x4>& boneWorldMatrices = worldMatrices[boneIndex];

fbxsdk::FbxNode* pParent = bones[boneIndex]->GetParent();
auto boneID = cd::BoneID::Min();
if (pParent->GetNodeAttribute()->GetAttributeType() == fbxsdk::FbxNodeAttribute::eSkeleton)
cd::BoneID parentBoneID = cd::BoneID::Invalid();
fbxsdk::FbxNodeAttribute* pParentNodeAttribute = pParent->GetNodeAttribute();
if (pParentNodeAttribute && fbxsdk::FbxNodeAttribute::eSkeleton == pParentNodeAttribute->GetAttributeType())
{
boneID = pSceneDatabase->GetBoneByName(pParent->GetName())->GetID();
parentBoneID = pSceneDatabase->GetBoneByName(pParent->GetName())->GetID();
}
std::vector<cd::Matrix4x4>& boneWorldInverseMatrices = worldInverseMatrices[boneID.Data()];

for (uint32_t trackIndex = 0; trackIndex < trackCount; ++trackIndex)
{
//Build local matrix;
cd::Matrix4x4 localMatrix;
if (pParent->GetNodeAttribute()->GetAttributeType() == fbxsdk::FbxNodeAttribute::eSkeleton)
if (parentBoneID.IsValid())
{
auto& boneWorldInverseMatrices = worldInverseMatrices[parentBoneID.Data()];
localMatrix = boneWorldInverseMatrices[trackIndex] * boneWorldMatrices[trackIndex];
}
else
{
localMatrix = boneWorldMatrices[trackIndex];
}

cd::Transform localTransform = cd::Transform(localMatrix.GetTranslation(),cd::Quaternion::FromMatrix(localMatrix.GetRotation()), localMatrix.GetScale());

//Fills corresponding track
const float t = times[trackIndex];
auto& cdTranslationKey = boneTrack.GetTranslationKeys()[trackIndex];
Expand Down
3 changes: 2 additions & 1 deletion private/Producers/FbxProducer/FbxProducerImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class FbxProducerImpl final
bool IsOptionEnabled(FbxProducerOptions option) const { return m_options.IsEnabled(option); }

private:
void TraverseBoneRecursively(fbxsdk::FbxNode* pSDKNode, cd::BoneID parentBoneID, cd::Skeleton& skeleton, cd::SceneDatabase* pSceneDatabase);
void TraverseNodeRecursively(fbxsdk::FbxNode* pSDKNode, cd::NodeID parentNodeID, cd::SceneDatabase* pSceneDatabase);

std::pair<cd::MaterialID, bool> AllocateMaterialID(const fbxsdk::FbxSurfaceMaterial* pSDKMaterial);
Expand All @@ -75,7 +76,7 @@ class FbxProducerImpl final

cd::SkinID ParseSkin(const fbxsdk::FbxSkin* pSkin, const cd::Mesh& sourceMesh, cd::SceneDatabase* pSceneDatabase);

cd::BoneID ParseBone(const fbxsdk::FbxNode* pSDKNode, cd::BoneID parentBoneID, cd::SceneDatabase* pSceneDatabase);
cd::BoneID ParseBone(fbxsdk::FbxNode* pSDKNode, cd::BoneID parentBoneID, cd::Skeleton& skeleton, cd::SceneDatabase* pSceneDatabase);
void ParseAnimation(fbxsdk::FbxScene* scene, cd::SceneDatabase* pSceneDatabase);

private:
Expand Down
1 change: 1 addition & 0 deletions private/Scene/Bone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ void Bone::Init(BoneID id, std::string name)

PIMPL_SIMPLE_TYPE_APIS(Bone, ID);
PIMPL_SIMPLE_TYPE_APIS(Bone, ParentID);
PIMPL_SIMPLE_TYPE_APIS(Bone, SkeletonID);
PIMPL_STRING_TYPE_APIS(Bone, Name);
PIMPL_COMPLEX_TYPE_APIS(Bone, Offset);
PIMPL_COMPLEX_TYPE_APIS(Bone, Transform);
Expand Down
1 change: 1 addition & 0 deletions private/Scene/BoneImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class BoneImpl final

IMPLEMENT_SIMPLE_TYPE_APIS(Bone, ID);
IMPLEMENT_SIMPLE_TYPE_APIS(Bone, ParentID);
IMPLEMENT_SIMPLE_TYPE_APIS(Bone, SkeletonID);
IMPLEMENT_STRING_TYPE_APIS(Bone, Name);
IMPLEMENT_COMPLEX_TYPE_APIS(Bone, Offset);
IMPLEMENT_COMPLEX_TYPE_APIS(Bone, Transform);
Expand Down
36 changes: 32 additions & 4 deletions private/Scene/SceneDatabaseImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ void SceneDatabaseImpl::Dump() const

for (cd::MeshID meshID : node.GetMeshIDs())
{
printf("\t[Associated Mesh %u]\n", meshID.Data());
printf("\t[Associated Mesh %u] Name = %s\n", meshID.Data(), GetMesh(meshID.Data()).GetName());
}
}
}
Expand Down Expand Up @@ -315,7 +315,7 @@ void SceneDatabaseImpl::Dump() const
for (const auto& [drawMeshID, drawPolygonGroupIndexes] : itDrawMeshPolygonGroups->second)
{
const auto& mesh = GetMesh(drawMeshID.Data());
printf("\t[Associated Mesh %u]\n", drawMeshID.Data());
printf("\t[Associated Mesh %u] Name = %s\n", drawMeshID.Data(), GetMesh(drawMeshID.Data()).GetName());
for (uint32_t drawPolygonGroupIndex : drawPolygonGroupIndexes)
{
printf("\t\t[PolygonGroup %u]\n", drawPolygonGroupIndex);
Expand Down Expand Up @@ -373,6 +373,18 @@ void SceneDatabaseImpl::Dump() const
for (const auto& skin : GetSkins())
{
printf("[Skin %u] Name : %s\n", skin.GetID().Data(), skin.GetName());

auto meshID = skin.GetMeshID();
if (meshID.IsValid())
{
printf("\t[Associated Mesh %u] Name = %s\n", meshID.Data(), GetMesh(meshID.Data()).GetName());
}

auto skeletonID = skin.GetSkeletonID();
if (skeletonID.IsValid())
{
printf("\t[Associated Skeleton %u] Name = %s\n", skeletonID.Data(), GetSkeleton(skeletonID.Data()).GetName());
}
}
}

Expand All @@ -382,6 +394,16 @@ void SceneDatabaseImpl::Dump() const
for (const auto& skeleton : GetSkeletons())
{
printf("[Skeleton %u] Name : %s\n", skeleton.GetID().Data(), skeleton.GetName());

for (auto rootBoneID : skeleton.GetRootBoneIDs())
{
printf("\t[Associated RootBone %u]\n", rootBoneID.Data());
}

for (auto boneID : skeleton.GetBoneIDs())
{
printf("\t[Associated Bone %u]\n", boneID.Data());
}
}
}

Expand All @@ -393,9 +415,10 @@ void SceneDatabaseImpl::Dump() const
printf("[Bone %u] Name : %s, ParentID : %u\n", bone.GetID().Data(), bone.GetName(), bone.GetParentID().Data());
details::Dump("\tRestPost", bone.GetOffset().Inverse());

for (const cd::BoneID childNodeID : bone.GetChildIDs())
printf("\t[Associated Skeleton %u]\n", bone.GetSkeletonID().Data());
for (auto childID : bone.GetChildIDs())
{
printf("\t[ChildBone %u]\n", childNodeID.Data());
printf("\t[ChildBone %u]\n", childID.Data());
}
}
}
Expand Down Expand Up @@ -461,12 +484,16 @@ void SceneDatabaseImpl::Validate() const
{
const cd::BlendShape& blendShape = GetBlendShape(blendShapeIndex);
assert(blendShapeIndex == blendShape.GetID().Data());
assert(blendShape.GetMeshID().IsValid());
assert(blendShape.GetMorphIDCount() > 0U);
}

for (uint32_t morphIndex = 0U; morphIndex < GetMorphCount(); ++morphIndex)
{
const cd::Morph& morph = GetMorph(morphIndex);
assert(morphIndex == morph.GetID().Data());
assert(morph.GetBlendShapeID().IsValid());
assert(morph.GetWeight() >= 0.0f && morph.GetWeight() <= 1.0f);
}

for (uint32_t materialIndex = 0U; materialIndex < GetMaterialCount(); ++materialIndex)
Expand All @@ -485,6 +512,7 @@ void SceneDatabaseImpl::Validate() const
{
const cd::Bone& bone = GetBone(boneIndex);
assert(boneIndex == bone.GetID().Data());
assert(bone.GetSkeletonID().IsValid());
}

for (uint32_t animationIndex = 0U; animationIndex < GetAnimationCount(); ++animationIndex)
Expand Down
Loading

0 comments on commit 2c79c89

Please sign in to comment.