From 8bd02e4bbc4d531926fd37c1863eeb37ec916e30 Mon Sep 17 00:00:00 2001 From: kearwood Date: Wed, 12 Dec 2012 09:32:53 +0000 Subject: [PATCH] Implemented logic to reduce number of bones to 4 and re-normalize the bone weights. Strongest weights are selected over smaller weights. --HG-- extra : convert_revision : svn%3A7752d6cf-9f14-4ad2-affc-04f1e67b81a5/trunk%40184 --- KREngine/KREngine.xcodeproj/project.pbxproj | 2 + KREngine/KREngine/Classes/KRModel.cpp | 2 +- KREngine/KREngine/Classes/KRModel.h | 2 +- KREngine/KREngine/Classes/KRResource+fbx.cpp | 104 +++++++++++++++++-- KREngine/KREngine/Classes/KRResource+obj.cpp | 7 +- 5 files changed, 106 insertions(+), 11 deletions(-) diff --git a/KREngine/KREngine.xcodeproj/project.pbxproj b/KREngine/KREngine.xcodeproj/project.pbxproj index f06ec17..7531d53 100644 --- a/KREngine/KREngine.xcodeproj/project.pbxproj +++ b/KREngine/KREngine.xcodeproj/project.pbxproj @@ -23,6 +23,7 @@ E416AA9A16713749000F6786 /* KRAnimationCurveManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E416AA9816713749000F6786 /* KRAnimationCurveManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; E416AA9C1671375C000F6786 /* KRAnimationCurveManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416AA9B1671375C000F6786 /* KRAnimationCurveManager.cpp */; }; E416AA9D1671375C000F6786 /* KRAnimationCurveManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416AA9B1671375C000F6786 /* KRAnimationCurveManager.cpp */; }; + E41843921678704000DBD6CF /* KRCollider.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 104A335C1672D31B001C8BA6 /* KRCollider.cpp */; }; E428C2F21669610500A16EDF /* KRAnimationManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E428C2F11669610500A16EDF /* KRAnimationManager.h */; }; E428C2F31669610500A16EDF /* KRAnimationManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E428C2F11669610500A16EDF /* KRAnimationManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; E428C2F51669611600A16EDF /* KRAnimationManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E428C2F41669611600A16EDF /* KRAnimationManager.cpp */; }; @@ -1091,6 +1092,7 @@ E4CA10EA1637BD2B005D9400 /* KRTexturePVR.cpp in Sources */, E4CA10F01637BD58005D9400 /* KRTextureTGA.cpp in Sources */, E4CA11791639CC90005D9400 /* KRViewport.cpp in Sources */, + E41843921678704000DBD6CF /* KRCollider.cpp in Sources */, E4324BAF16444E120043185B /* KRParticleSystemNewtonian.cpp in Sources */, E4324BB0164458930043185B /* KRParticleSystem.cpp in Sources */, E428C2F61669611600A16EDF /* KRAnimationManager.cpp in Sources */, diff --git a/KREngine/KREngine/Classes/KRModel.cpp b/KREngine/KREngine/Classes/KRModel.cpp index b4ee50a..0c0c62b 100644 --- a/KREngine/KREngine/Classes/KRModel.cpp +++ b/KREngine/KREngine/Classes/KRModel.cpp @@ -284,7 +284,7 @@ unsigned char *KRModel::getVertexData() const { } -void KRModel::LoadData(std::vector vertices, std::vector uva, std::vector uvb, std::vector normals, std::vector tangents, std::vector submesh_starts, std::vector submesh_lengths, std::vector material_names) { +void KRModel::LoadData(std::vector vertices, std::vector uva, std::vector uvb, std::vector normals, std::vector tangents, std::vector submesh_starts, std::vector submesh_lengths, std::vector material_names, std::list bone_names, std::vector > bone_indexes, std::vector > bone_weights) { clearData(); diff --git a/KREngine/KREngine/Classes/KRModel.h b/KREngine/KREngine/Classes/KRModel.h index 760195e..509a941 100644 --- a/KREngine/KREngine/Classes/KRModel.h +++ b/KREngine/KREngine/Classes/KRModel.h @@ -78,7 +78,7 @@ public: virtual std::string getExtension(); virtual bool save(const std::string& path); - void LoadData(std::vector vertices, std::vector uva, std::vector uvb, std::vector normals, std::vector tangents, std::vector submesh_starts, std::vector submesh_lengths, std::vector material_names); + void LoadData(std::vector vertices, std::vector uva, std::vector uvb, std::vector normals, std::vector tangents, std::vector submesh_starts, std::vector submesh_lengths, std::vector material_names, std::list bone_names, std::vector > bone_indexes, std::vector > bone_weights); void loadPack(KRDataBlock *data); diff --git a/KREngine/KREngine/Classes/KRResource+fbx.cpp b/KREngine/KREngine/Classes/KRResource+fbx.cpp index 7b2a99c..b4094c9 100644 --- a/KREngine/KREngine/Classes/KRResource+fbx.cpp +++ b/KREngine/KREngine/Classes/KRResource+fbx.cpp @@ -398,7 +398,7 @@ KRAnimationLayer *LoadAnimationLayer(KRContext &context, FbxAnimLayer *pAnimLaye // // pNode->SetPivotState(KFbxNode::eSourcePivot, KFbxNode::ePivotActive); // pNode->SetPivotState(KFbxNode::eDestinationPivot, KFbxNode::ePivotActive); -// +// // // Pass the current value to the source pivot. //// * - Rotation offset (Roff) //// * - Rotation pivot (Rp) @@ -700,13 +700,86 @@ KRNode *LoadMesh(KRNode *parent_node, std::vector &resources, FbxG KFbxMesh* pSourceMesh = (KFbxMesh*) pNode->GetNodeAttribute(); KFbxMesh* pMesh = pGeometryConverter->TriangulateMesh(pSourceMesh); - int skin_count = pMesh->GetDeformerCount(FbxDeformer::eSkin); - for(int skin_index=0; skin_indexGetDeformer(skin_index, FbxDeformer::eSkin); - skin->GetControlPointBlendWeights() + int control_point_count = pMesh->GetControlPointsCount(); + KFbxVector4* control_points = pMesh->GetControlPoints(); + + const int MAX_BONE_WEIGHTS = 4; + + struct control_point_weight_info { + float weights[MAX_BONE_WEIGHTS]; + int bone_indexes[MAX_BONE_WEIGHTS]; + }; + + control_point_weight_info *control_point_weights = new control_point_weight_info[control_point_count]; + for(int control_point=0; control_point < control_point_count; control_point++) { + for(int i=0; iGetControlPoints(); + std::list bone_names; + bool too_many_bone_weights = false; + + // Collect the top 4 bone weights per vertex ... + int skin_count = pMesh->GetDeformerCount(FbxDeformer::eSkin); + int target_bone_index = 0; + for(int skin_index=0; skin_indexGetDeformer(skin_index, FbxDeformer::eSkin); + int cluster_count = skin->GetClusterCount(); + printf(" Found skin with %i clusters.\n", cluster_count); + for(int cluster_index=0; cluster_index < cluster_count; cluster_index++) { + FbxCluster *cluster = skin->GetCluster(cluster_index); + if(cluster->GetLinkMode() != FbxCluster::eNormalize) { + printf(" Warning! link mode not supported.\n"); + } + std::string bone_name = GetFbxObjectName(cluster->GetLink()); + bone_names.push_back(bone_name); + + int cluster_control_point_count = cluster->GetControlPointIndicesCount(); + for(int control_point=0; control_pointGetControlPointIndices()[control_point]]; + float bone_weight = cluster->GetControlPointWeights()[control_point]; + if(bone_weight > weight_info.weights[MAX_BONE_WEIGHTS - 1]) { + if(weight_info.weights[MAX_BONE_WEIGHTS - 1] != 0.0f) { + too_many_bone_weights = true; + } + weight_info.weights[MAX_BONE_WEIGHTS - 1] = bone_weight; + weight_info.bone_indexes[MAX_BONE_WEIGHTS - 1] = target_bone_index; + for(int bone_index=MAX_BONE_WEIGHTS - 1; bone_index >=0; bone_index--) { + if(bone_weight > weight_info.weights[bone_index]) { + weight_info.weights[bone_index+1] = weight_info.weights[bone_index]; + weight_info.bone_indexes[bone_index+1] = weight_info.bone_indexes[bone_index]; + weight_info.weights[bone_index] = bone_weight; + weight_info.bone_indexes[bone_index] = target_bone_index; + } + } + } else { + too_many_bone_weights = true; + } + } + target_bone_index++; + } + } + + if(too_many_bone_weights) { + printf(" WARNING! - Clipped bone weights to limit of %i per vertex (selecting largest weights and re-normalizing).\n", MAX_BONE_WEIGHTS); + } + // Normalize bone weights + if(bone_names.size() > 0) { + for(int control_point_index=0; control_point_index < control_point_count; control_point_index++) { + control_point_weight_info &weight_info = control_point_weights[control_point_index]; + float total_weights = 0.0f; + for(int i=0; i < MAX_BONE_WEIGHTS; i++) { + total_weights += weight_info.weights[i]; + } + if(total_weights == 0.0f) total_weights = 1.0f; // Prevent any divisions by zero + for(int i=0; i < MAX_BONE_WEIGHTS; i++) { + weight_info.weights[i] = weight_info.weights[i] / total_weights; + } + } + } int polygon_count = pMesh->GetPolygonCount(); int uv_count = pMesh->GetElementUVCount(); @@ -718,6 +791,9 @@ KRNode *LoadMesh(KRNode *parent_node, std::vector &resources, FbxG printf(" Polygon Count: %i (before triangulation: %i)\n", polygon_count, pSourceMesh->GetPolygonCount()); + std::vector > bone_weights; + std::vector > bone_indexes; + std::vector vertices; std::vector uva; std::vector uvb; @@ -763,6 +839,18 @@ KRNode *LoadMesh(KRNode *parent_node, std::vector &resources, FbxG KFbxVector4 v = control_points[lControlPointIndex]; vertices.push_back(KRVector3(v[0], v[1], v[2])); + if(bone_names.size() > 0) { + control_point_weight_info &weight_info = control_point_weights[lControlPointIndex]; + std::vector vertex_bone_indexes; + std::vector vertex_bone_weights; + for(int i=0; i &resources, FbxG } } } - + delete control_point_weights; // ----====---- Generate Output Mesh Object ----====---- KRModel *new_mesh = new KRModel(parent_node->getContext(), pNode->GetName()); - new_mesh->LoadData(vertices, uva, uvb, normals, tangents, submesh_starts, submesh_lengths, material_names); + new_mesh->LoadData(vertices, uva, uvb, normals, tangents, submesh_starts, submesh_lengths, material_names, bone_names, bone_indexes, bone_weights); resources.push_back(new_mesh); if(new_mesh->getLODCoverage() == 100) { diff --git a/KREngine/KREngine/Classes/KRResource+obj.cpp b/KREngine/KREngine/Classes/KRResource+obj.cpp index 4c8f2d5..95e0433 100644 --- a/KREngine/KREngine/Classes/KRResource+obj.cpp +++ b/KREngine/KREngine/Classes/KRResource+obj.cpp @@ -333,7 +333,12 @@ std::vector KRResource::LoadObj(KRContext &context, const std::str delete pNewMaterial; } - new_mesh->LoadData(vertices, uva, uvb, normals, tangents, submesh_starts, submesh_lengths, material_names); + // TODO: Bones not yet supported for OBJ + std::list bone_names; + std::vector > bone_indexes; + std::vector > bone_weights; + + new_mesh->LoadData(vertices, uva, uvb, normals, tangents, submesh_starts, submesh_lengths, material_names, bone_names, bone_indexes, bone_weights); } if(pFaces) {