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
This commit is contained in:
kearwood
2012-12-12 09:32:53 +00:00
parent 4f5fd10e71
commit 8bd02e4bbc
5 changed files with 106 additions and 11 deletions

View File

@@ -23,6 +23,7 @@
E416AA9A16713749000F6786 /* KRAnimationCurveManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E416AA9816713749000F6786 /* KRAnimationCurveManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 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 */; }; E416AA9C1671375C000F6786 /* KRAnimationCurveManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416AA9B1671375C000F6786 /* KRAnimationCurveManager.cpp */; };
E416AA9D1671375C000F6786 /* 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 */; }; 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, ); }; }; 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 */; }; E428C2F51669611600A16EDF /* KRAnimationManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E428C2F41669611600A16EDF /* KRAnimationManager.cpp */; };
@@ -1091,6 +1092,7 @@
E4CA10EA1637BD2B005D9400 /* KRTexturePVR.cpp in Sources */, E4CA10EA1637BD2B005D9400 /* KRTexturePVR.cpp in Sources */,
E4CA10F01637BD58005D9400 /* KRTextureTGA.cpp in Sources */, E4CA10F01637BD58005D9400 /* KRTextureTGA.cpp in Sources */,
E4CA11791639CC90005D9400 /* KRViewport.cpp in Sources */, E4CA11791639CC90005D9400 /* KRViewport.cpp in Sources */,
E41843921678704000DBD6CF /* KRCollider.cpp in Sources */,
E4324BAF16444E120043185B /* KRParticleSystemNewtonian.cpp in Sources */, E4324BAF16444E120043185B /* KRParticleSystemNewtonian.cpp in Sources */,
E4324BB0164458930043185B /* KRParticleSystem.cpp in Sources */, E4324BB0164458930043185B /* KRParticleSystem.cpp in Sources */,
E428C2F61669611600A16EDF /* KRAnimationManager.cpp in Sources */, E428C2F61669611600A16EDF /* KRAnimationManager.cpp in Sources */,

View File

@@ -284,7 +284,7 @@ unsigned char *KRModel::getVertexData() const {
} }
void KRModel::LoadData(std::vector<KRVector3> vertices, std::vector<KRVector2> uva, std::vector<KRVector2> uvb, std::vector<KRVector3> normals, std::vector<KRVector3> tangents, std::vector<int> submesh_starts, std::vector<int> submesh_lengths, std::vector<std::string> material_names) { void KRModel::LoadData(std::vector<KRVector3> vertices, std::vector<KRVector2> uva, std::vector<KRVector2> uvb, std::vector<KRVector3> normals, std::vector<KRVector3> tangents, std::vector<int> submesh_starts, std::vector<int> submesh_lengths, std::vector<std::string> material_names, std::list<std::string> bone_names, std::vector<std::vector<int> > bone_indexes, std::vector<std::vector<float> > bone_weights) {
clearData(); clearData();

View File

@@ -78,7 +78,7 @@ public:
virtual std::string getExtension(); virtual std::string getExtension();
virtual bool save(const std::string& path); virtual bool save(const std::string& path);
void LoadData(std::vector<KRVector3> vertices, std::vector<KRVector2> uva, std::vector<KRVector2> uvb, std::vector<KRVector3> normals, std::vector<KRVector3> tangents, std::vector<int> submesh_starts, std::vector<int> submesh_lengths, std::vector<std::string> material_names); void LoadData(std::vector<KRVector3> vertices, std::vector<KRVector2> uva, std::vector<KRVector2> uvb, std::vector<KRVector3> normals, std::vector<KRVector3> tangents, std::vector<int> submesh_starts, std::vector<int> submesh_lengths, std::vector<std::string> material_names, std::list<std::string> bone_names, std::vector<std::vector<int> > bone_indexes, std::vector<std::vector<float> > bone_weights);
void loadPack(KRDataBlock *data); void loadPack(KRDataBlock *data);

View File

@@ -398,7 +398,7 @@ KRAnimationLayer *LoadAnimationLayer(KRContext &context, FbxAnimLayer *pAnimLaye
// //
// pNode->SetPivotState(KFbxNode::eSourcePivot, KFbxNode::ePivotActive); // pNode->SetPivotState(KFbxNode::eSourcePivot, KFbxNode::ePivotActive);
// pNode->SetPivotState(KFbxNode::eDestinationPivot, KFbxNode::ePivotActive); // pNode->SetPivotState(KFbxNode::eDestinationPivot, KFbxNode::ePivotActive);
// //
// // Pass the current value to the source pivot. // // Pass the current value to the source pivot.
//// * - Rotation offset (Roff) //// * - Rotation offset (Roff)
//// * - Rotation pivot (Rp) //// * - Rotation pivot (Rp)
@@ -700,13 +700,86 @@ KRNode *LoadMesh(KRNode *parent_node, std::vector<KRResource *> &resources, FbxG
KFbxMesh* pSourceMesh = (KFbxMesh*) pNode->GetNodeAttribute(); KFbxMesh* pSourceMesh = (KFbxMesh*) pNode->GetNodeAttribute();
KFbxMesh* pMesh = pGeometryConverter->TriangulateMesh(pSourceMesh); KFbxMesh* pMesh = pGeometryConverter->TriangulateMesh(pSourceMesh);
int skin_count = pMesh->GetDeformerCount(FbxDeformer::eSkin); int control_point_count = pMesh->GetControlPointsCount();
for(int skin_index=0; skin_index<skin_count; skin_index++) { KFbxVector4* control_points = pMesh->GetControlPoints();
FbxSkin *skin = (FbxSkin *)pMesh->GetDeformer(skin_index, FbxDeformer::eSkin);
skin->GetControlPointBlendWeights() 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; i<MAX_BONE_WEIGHTS; i++) {
control_point_weights[control_point].weights[i] = 0.0f;
control_point_weights[control_point].bone_indexes[i] = 0;
}
} }
KFbxVector4* control_points = pMesh->GetControlPoints(); std::list<std::string> 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_index<skin_count; skin_index++) {
FbxSkin *skin = (FbxSkin *)pMesh->GetDeformer(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_point<cluster_control_point_count; control_point++) {
control_point_weight_info &weight_info = control_point_weights[cluster->GetControlPointIndices()[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 polygon_count = pMesh->GetPolygonCount();
int uv_count = pMesh->GetElementUVCount(); int uv_count = pMesh->GetElementUVCount();
@@ -718,6 +791,9 @@ KRNode *LoadMesh(KRNode *parent_node, std::vector<KRResource *> &resources, FbxG
printf(" Polygon Count: %i (before triangulation: %i)\n", polygon_count, pSourceMesh->GetPolygonCount()); printf(" Polygon Count: %i (before triangulation: %i)\n", polygon_count, pSourceMesh->GetPolygonCount());
std::vector<std::vector<float> > bone_weights;
std::vector<std::vector<int> > bone_indexes;
std::vector<KRVector3> vertices; std::vector<KRVector3> vertices;
std::vector<KRVector2> uva; std::vector<KRVector2> uva;
std::vector<KRVector2> uvb; std::vector<KRVector2> uvb;
@@ -763,6 +839,18 @@ KRNode *LoadMesh(KRNode *parent_node, std::vector<KRResource *> &resources, FbxG
KFbxVector4 v = control_points[lControlPointIndex]; KFbxVector4 v = control_points[lControlPointIndex];
vertices.push_back(KRVector3(v[0], v[1], v[2])); 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<int> vertex_bone_indexes;
std::vector<float> vertex_bone_weights;
for(int i=0; i<MAX_BONE_WEIGHTS; i++) {
vertex_bone_indexes.push_back(weight_info.bone_indexes[i]);
vertex_bone_weights.push_back(weight_info.weights[i]);
}
bone_indexes.push_back(vertex_bone_indexes);
bone_weights.push_back(vertex_bone_weights);
}
KRVector2 new_uva = KRVector2(0.0, 0.0); KRVector2 new_uva = KRVector2(0.0, 0.0);
KRVector2 new_uvb = KRVector2(0.0, 0.0); KRVector2 new_uvb = KRVector2(0.0, 0.0);
@@ -990,14 +1078,14 @@ KRNode *LoadMesh(KRNode *parent_node, std::vector<KRResource *> &resources, FbxG
} }
} }
} }
delete control_point_weights;
// ----====---- Generate Output Mesh Object ----====---- // ----====---- Generate Output Mesh Object ----====----
KRModel *new_mesh = new KRModel(parent_node->getContext(), pNode->GetName()); 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); resources.push_back(new_mesh);
if(new_mesh->getLODCoverage() == 100) { if(new_mesh->getLODCoverage() == 100) {

View File

@@ -333,7 +333,12 @@ std::vector<KRResource *> KRResource::LoadObj(KRContext &context, const std::str
delete pNewMaterial; 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<std::string> bone_names;
std::vector<std::vector<int> > bone_indexes;
std::vector<std::vector<float> > bone_weights;
new_mesh->LoadData(vertices, uva, uvb, normals, tangents, submesh_starts, submesh_lengths, material_names, bone_names, bone_indexes, bone_weights);
} }
if(pFaces) { if(pFaces) {