diff options
author | Juha Mäki-Kanto <ih5235252@gmail.com> | 2012-02-18 20:20:24 +0400 |
---|---|---|
committer | Juha Mäki-Kanto <ih5235252@gmail.com> | 2012-02-18 20:20:24 +0400 |
commit | 7beddb750610982ebccfd64d87759baa91e011a5 (patch) | |
tree | b0b810a6095f18796c1b3eeaa644a87efbf2af13 /source/blender | |
parent | e6b708b36bb77ff2287439f20fc79097c275c822 (diff) |
Collada export: changes to joints/weights in skincontroller
- Collecting joints/weights in one place, it's easier to exclude zero weights or vertexgroups with no matching bone than trying to match same logic in multiple places.
- Still not exporting -1 joints for vertices without weights, but also not outputting -1 joint + weight for each vertexgroup without a matching bone.
- The exported weights are now normalized.
Last I tested this patch stopped 3ds Max crashing on import of file from #29465 (opencollada / internal .dae).
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/collada/ArmatureExporter.cpp | 124 | ||||
-rw-r--r-- | source/blender/collada/ArmatureExporter.h | 7 |
2 files changed, 80 insertions, 51 deletions
diff --git a/source/blender/collada/ArmatureExporter.cpp b/source/blender/collada/ArmatureExporter.cpp index 0e89f2db74b..277b1896397 100644 --- a/source/blender/collada/ArmatureExporter.cpp +++ b/source/blender/collada/ArmatureExporter.cpp @@ -296,10 +296,64 @@ void ArmatureExporter::export_controller(Object* ob, Object *ob_arm) std::string joints_source_id = add_joints_source(ob_arm, &ob->defbase, controller_id); std::string inv_bind_mat_source_id = add_inv_bind_mats_source(ob_arm, &ob->defbase, controller_id); - std::string weights_source_id = add_weights_source(me, controller_id); + std::list<int> vcounts; + std::list<int> joints; + std::list<float> weights; + + { + int i, j; + + // def group index -> joint index + std::vector<int> joint_index_by_def_index; + bDeformGroup *def; + + for (def = (bDeformGroup*)ob->defbase.first, i = 0, j = 0; def; def = def->next, i++) { + if (is_bone_defgroup(ob_arm, def)) + joint_index_by_def_index.push_back(j++); + else + joint_index_by_def_index.push_back(-1); + } + + for (i = 0; i < me->totvert; i++) { + MDeformVert *vert = &me->dvert[i]; + std::map<int, float> jw; + + // We're normalizing the weights later + float sumw = 0.0f; + + for (j = 0; j < vert->totweight; j++) { + int joint_index = joint_index_by_def_index[vert->dw[j].def_nr]; + if(joint_index != -1 && vert->dw[j].weight > 0.0f) + { + jw[joint_index] += vert->dw[j].weight; + sumw += vert->dw[j].weight; + } + } + + if(sumw > 0.0f) + { + float invsumw = 1.0f/sumw; + vcounts.push_back(jw.size()); + for(std::map<int, float>::iterator m = jw.begin(); m != jw.end(); ++m) + { + joints.push_back((*m).first); + weights.push_back(invsumw*(*m).second); + } + } + else + { + vcounts.push_back(0); + /*vcounts.push_back(1); + joints.push_back(-1); + weights.push_back(1.0f);*/ + } + } + } + + std::string weights_source_id = add_weights_source(me, controller_id, weights); add_joints_element(&ob->defbase, joints_source_id, inv_bind_mat_source_id); - add_vertex_weights_element(weights_source_id, joints_source_id, me, ob_arm, &ob->defbase); + add_vertex_weights_element(weights_source_id, joints_source_id, vcounts, joints); closeSkin(); closeController(); @@ -445,21 +499,14 @@ bool ArmatureExporter::is_bone_defgroup(Object *ob_arm, bDeformGroup* def) return get_bone_from_defgroup(ob_arm, def) != NULL; } -std::string ArmatureExporter::add_weights_source(Mesh *me, const std::string& controller_id) +std::string ArmatureExporter::add_weights_source(Mesh *me, const std::string& controller_id, const std::list<float>& weights) { std::string source_id = controller_id + WEIGHTS_SOURCE_ID_SUFFIX; - int i; - int totweight = 0; - - for (i = 0; i < me->totvert; i++) { - totweight += me->dvert[i].totweight; - } - COLLADASW::FloatSourceF source(mSW); source.setId(source_id); source.setArrayId(source_id + ARRAY_ID_SUFFIX); - source.setAccessorCount(totweight); + source.setAccessorCount(weights.size()); source.setAccessorStride(1); COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); @@ -467,13 +514,8 @@ std::string ArmatureExporter::add_weights_source(Mesh *me, const std::string& co source.prepareToAppendValues(); - // NOTE: COLLADA spec says weights should be normalized - - for (i = 0; i < me->totvert; i++) { - MDeformVert *vert = &me->dvert[i]; - for (int j = 0; j < vert->totweight; j++) { - source.appendValues(vert->dw[j].weight); - } + for(std::list<float>::const_iterator i = weights.begin(); i != weights.end(); ++i) { + source.appendValues(*i); } source.finish(); @@ -481,11 +523,12 @@ std::string ArmatureExporter::add_weights_source(Mesh *me, const std::string& co return source_id; } -void ArmatureExporter::add_vertex_weights_element(const std::string& weights_source_id, const std::string& joints_source_id, Mesh *me, - Object *ob_arm, ListBase *defbase) +void ArmatureExporter::add_vertex_weights_element(const std::string& weights_source_id, const std::string& joints_source_id, + const std::list<int>& vcounts, + const std::list<int>& joints) { - COLLADASW::VertexWeightsElement weights(mSW); - COLLADASW::InputList &input = weights.getInputList(); + COLLADASW::VertexWeightsElement weightselem(mSW); + COLLADASW::InputList &input = weightselem.getInputList(); int offset = 0; input.push_back(COLLADASW::Input(COLLADASW::InputSemantic::JOINT, // constant declared in COLLADASWInputList.h @@ -493,40 +536,25 @@ void ArmatureExporter::add_vertex_weights_element(const std::string& weights_sou input.push_back(COLLADASW::Input(COLLADASW::InputSemantic::WEIGHT, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, weights_source_id), offset++)); - weights.setCount(me->totvert); + weightselem.setCount(vcounts.size()); // write number of deformers per vertex - COLLADASW::PrimitivesBase::VCountList vcount; - int i; - for (i = 0; i < me->totvert; i++) { - vcount.push_back(me->dvert[i].totweight); - } + COLLADASW::PrimitivesBase::VCountList vcountlist; - weights.prepareToAppendVCountValues(); - weights.appendVertexCount(vcount); + vcountlist.resize(vcounts.size()); + std::copy(vcounts.begin(), vcounts.end(), vcountlist.begin()); - // def group index -> joint index - std::map<int, int> joint_index_by_def_index; - bDeformGroup *def; - int j; - for (def = (bDeformGroup*)defbase->first, i = 0, j = 0; def; def = def->next, i++) { - if (is_bone_defgroup(ob_arm, def)) - joint_index_by_def_index[i] = j++; - else - joint_index_by_def_index[i] = -1; - } + weightselem.prepareToAppendVCountValues(); + weightselem.appendVertexCount(vcountlist); - weights.CloseVCountAndOpenVElement(); + weightselem.CloseVCountAndOpenVElement(); // write deformer index - weight index pairs int weight_index = 0; - for (i = 0; i < me->totvert; i++) { - MDeformVert *dvert = &me->dvert[i]; - for (int j = 0; j < dvert->totweight; j++) { - weights.appendValues(joint_index_by_def_index[dvert->dw[j].def_nr]); - weights.appendValues(weight_index++); - } + for(std::list<int>::const_iterator i = joints.begin(); i != joints.end(); ++i) + { + weightselem.appendValues(*i, weight_index++); } - weights.finish(); + weightselem.finish(); } diff --git a/source/blender/collada/ArmatureExporter.h b/source/blender/collada/ArmatureExporter.h index 925e65c9b69..9d64664fa63 100644 --- a/source/blender/collada/ArmatureExporter.h +++ b/source/blender/collada/ArmatureExporter.h @@ -111,10 +111,11 @@ private: bool is_bone_defgroup(Object *ob_arm, bDeformGroup* def); - std::string add_weights_source(Mesh *me, const std::string& controller_id); + std::string add_weights_source(Mesh *me, const std::string& controller_id, + const std::list<float>& weights); - void add_vertex_weights_element(const std::string& weights_source_id, const std::string& joints_source_id, Mesh *me, - Object *ob_arm, ListBase *defbase); + void add_vertex_weights_element(const std::string& weights_source_id, const std::string& joints_source_id, + const std::list<int>& vcount, const std::list<int>& joints); }; #endif |