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).
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user