Blender V4.3
ControllerExporter.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2010-2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "COLLADASWBaseInputElement.h"
10#include "COLLADASWInstanceController.h"
11#include "COLLADASWPrimitves.h"
12#include "COLLADASWSource.h"
13
14#include "DNA_action_types.h"
15#include "DNA_meshdata_types.h"
16#include "DNA_modifier_types.h"
17
18#include "BKE_action.hh"
19#include "BKE_armature.hh"
20#include "BKE_deform.hh"
21#include "BKE_global.hh"
22#include "BKE_idprop.hh"
23#include "BKE_lib_id.hh"
24#include "BKE_mesh.hh"
25
26#include "ED_armature.hh"
27
28#include "BLI_listbase.h"
29#include "BLI_math_matrix.h"
30
31#include "ArmatureExporter.h"
32#include "ControllerExporter.h"
33#include "GeometryExporter.h"
34#include "SceneExporter.h"
35
36#include "collada_utils.h"
37
39{
40 return bc_get_assigned_armature(ob) != nullptr;
41}
42
43void ControllerExporter::write_bone_URLs(COLLADASW::InstanceController &ins,
44 Object *ob_arm,
45 Bone *bone)
46{
47 if (bc_is_root_bone(bone, this->export_settings.get_deform_bones_only())) {
48 std::string node_id = translate_id(id_name(ob_arm) + "_" + bone->name);
49 ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, node_id));
50 }
51 else {
52 LISTBASE_FOREACH (Bone *, child, &bone->childbase) {
53 write_bone_URLs(ins, ob_arm, child);
54 }
55 }
56}
57
59{
60 Object *ob_arm = bc_get_assigned_armature(ob);
61 bArmature *arm = (bArmature *)ob_arm->data;
62
63 const std::string &controller_id = get_controller_id(ob_arm, ob);
64
65 COLLADASW::InstanceController ins(mSW);
66 ins.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, controller_id));
67
68 Mesh *mesh = (Mesh *)ob->data;
69 if (mesh->deform_verts().is_empty()) {
70 return false;
71 }
72
73 /* write root bone URLs */
74 LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) {
75 write_bone_URLs(ins, ob_arm, bone);
76 }
77
79 ins.getBindMaterial(), ob, this->export_settings.get_active_uv_only());
80
81 ins.add();
82 return true;
83}
84
86{
87 Scene *sce = blender_context.get_scene();
88 openLibrary();
89
92 sce, *this, this->export_settings.get_export_set());
93
94 closeLibrary();
95}
96
98{
99 Object *ob_arm = bc_get_assigned_armature(ob);
100 Key *key = BKE_key_from_object(ob);
101
102 if (ob_arm) {
103 export_skin_controller(ob, ob_arm);
104 }
105 if (key && this->export_settings.get_include_shapekeys()) {
106 export_morph_controller(ob, key);
107 }
108}
109#if 0
110
111bool ArmatureExporter::already_written(Object *ob_arm)
112{
113 return std::find(written_armatures.begin(), written_armatures.end(), ob_arm) !=
114 written_armatures.end();
115}
116
117void ArmatureExporter::wrote(Object *ob_arm)
118{
119 written_armatures.push_back(ob_arm);
120}
121
122void ArmatureExporter::find_objects_using_armature(Object *ob_arm,
123 std::vector<Object *> &objects,
124 Scene *sce)
125{
126 objects.clear();
127
128 Base *base = (Base *)sce->base.first;
129 while (base) {
130 Object *ob = base->object;
131
132 if (ob->type == OB_MESH && get_assigned_armature(ob) == ob_arm) {
133 objects.push_back(ob);
134 }
135
136 base = base->next;
137 }
138}
139#endif
140
141std::string ControllerExporter::get_controller_id(Object *ob_arm, Object *ob)
142{
143 return translate_id(id_name(ob_arm)) + "_" + translate_id(id_name(ob)) +
144 SKIN_CONTROLLER_ID_SUFFIX;
145}
146
147std::string ControllerExporter::get_controller_id(Key *key, Object *ob)
148{
149 return translate_id(id_name(ob)) + MORPH_CONTROLLER_ID_SUFFIX;
150}
151
152void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
153{
154 /* joint names
155 * joint inverse bind matrices
156 * vertex weights */
157
158 /* input:
159 * joint names: ob -> vertex group names
160 * vertex group weights: mesh->dvert -> groups -> index, weight */
161
162 bool use_instantiation = this->export_settings.get_use_object_instantiation();
163 Mesh *mesh;
164
165 if (((Mesh *)ob->data)->deform_verts().is_empty()) {
166 return;
167 }
168
169 mesh = bc_get_mesh_copy(blender_context,
170 ob,
171 this->export_settings.get_export_mesh_type(),
172 this->export_settings.get_apply_modifiers(),
173 this->export_settings.get_triangulate());
174
175 std::string controller_name = id_name(ob_arm);
176 std::string controller_id = get_controller_id(ob_arm, ob);
177
178 openSkin(controller_id,
179 controller_name,
180 COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob, use_instantiation)));
181
182 add_bind_shape_mat(ob);
183
184 const ListBase *defbase = BKE_object_defgroup_list(ob);
185 std::string joints_source_id = add_joints_source(ob_arm, defbase, controller_id);
186 std::string inv_bind_mat_source_id = add_inv_bind_mats_source(ob_arm, defbase, controller_id);
187
188 std::list<int> vcounts;
189 std::list<int> joints;
190 std::list<float> weights;
191
192 {
193 int i, j;
194
195 /* def group index -> joint index */
196 std::vector<int> joint_index_by_def_index;
197 const bDeformGroup *def;
198
199 for (def = (const bDeformGroup *)defbase->first, i = 0, j = 0; def; def = def->next, i++) {
200 if (is_bone_defgroup(ob_arm, def)) {
201 joint_index_by_def_index.push_back(j++);
202 }
203 else {
204 joint_index_by_def_index.push_back(-1);
205 }
206 }
207
208 const MDeformVert *dvert = mesh->deform_verts().data();
209 int oob_counter = 0;
210 for (i = 0; i < mesh->verts_num; i++) {
211 const MDeformVert *vert = &dvert[i];
212 std::map<int, float> jw;
213
214 /* We're normalizing the weights later */
215 float sumw = 0.0f;
216
217 for (j = 0; j < vert->totweight; j++) {
218 uint idx = vert->dw[j].def_nr;
219 if (idx >= joint_index_by_def_index.size()) {
220 /* XXX: Maybe better find out where and
221 * why the Out Of Bound indexes get created? */
222 oob_counter += 1;
223 }
224 else {
225 int joint_index = joint_index_by_def_index[idx];
226 if (joint_index != -1 && vert->dw[j].weight > 0.0f) {
227 jw[joint_index] += vert->dw[j].weight;
228 sumw += vert->dw[j].weight;
229 }
230 }
231 }
232
233 if (sumw > 0.0f) {
234 float invsumw = 1.0f / sumw;
235 vcounts.push_back(jw.size());
236 for (auto &index_and_weight : jw) {
237 joints.push_back(index_and_weight.first);
238 weights.push_back(invsumw * index_and_weight.second);
239 }
240 }
241 else {
242 vcounts.push_back(0);
243#if 0
244 vcounts.push_back(1);
245 joints.push_back(-1);
246 weights.push_back(1.0f);
247#endif
248 }
249 }
250
251 if (oob_counter > 0) {
252 fprintf(stderr,
253 "Ignored %d Vertex weights which use index to non existing VGroup %zu.\n",
254 oob_counter,
255 joint_index_by_def_index.size());
256 }
257 }
258
259 std::string weights_source_id = add_weights_source(mesh, controller_id, weights);
260 add_joints_element(defbase, joints_source_id, inv_bind_mat_source_id);
261 add_vertex_weights_element(weights_source_id, joints_source_id, vcounts, joints);
262
263 BKE_id_free(nullptr, mesh);
264
265 closeSkin();
266 closeController();
267}
268
269void ControllerExporter::export_morph_controller(Object *ob, Key *key)
270{
271 bool use_instantiation = this->export_settings.get_use_object_instantiation();
272 Mesh *mesh;
273
274 mesh = bc_get_mesh_copy(blender_context,
275 ob,
276 this->export_settings.get_export_mesh_type(),
277 this->export_settings.get_apply_modifiers(),
278 this->export_settings.get_triangulate());
279
280 std::string controller_name = id_name(ob) + "-morph";
281 std::string controller_id = get_controller_id(key, ob);
282
283 openMorph(
284 controller_id,
285 controller_name,
286 COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob, use_instantiation)));
287
288 std::string targets_id = add_morph_targets(key, ob);
289 std::string morph_weights_id = add_morph_weights(key, ob);
290
291 COLLADASW::TargetsElement targets(mSW);
292
293 COLLADASW::InputList &input = targets.getInputList();
294
295 input.push_back(COLLADASW::Input(
296 COLLADASW::InputSemantic::MORPH_TARGET, /* constant declared in COLLADASWInputList.h */
297 COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, targets_id)));
298 input.push_back(
299 COLLADASW::Input(COLLADASW::InputSemantic::MORPH_WEIGHT,
300 COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, morph_weights_id)));
301 targets.add();
302
303 BKE_id_free(nullptr, mesh);
304
305 /* support for animations
306 * can also try the base element and param alternative */
307 add_weight_extras(key);
308 closeMorph();
309 closeController();
310}
311
312std::string ControllerExporter::add_morph_targets(Key *key, Object *ob)
313{
314 std::string source_id = translate_id(id_name(ob)) + TARGETS_SOURCE_ID_SUFFIX;
315
316 COLLADASW::IdRefSource source(mSW);
317 source.setId(source_id);
318 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
319 source.setAccessorCount(key->totkey - 1);
320 source.setAccessorStride(1);
321
322 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
323 param.push_back("IDREF");
324
325 source.prepareToAppendValues();
326
327 KeyBlock *kb = (KeyBlock *)key->block.first;
328 /* skip the basis */
329 kb = kb->next;
330 for (; kb; kb = kb->next) {
331 std::string geom_id = get_geometry_id(ob, false) + "_morph_" + translate_id(kb->name);
332 source.appendValues(geom_id);
333 }
334
335 source.finish();
336
337 return source_id;
338}
339
340std::string ControllerExporter::add_morph_weights(Key *key, Object *ob)
341{
342 std::string source_id = translate_id(id_name(ob)) + WEIGHTS_SOURCE_ID_SUFFIX;
343
344 COLLADASW::FloatSourceF source(mSW);
345 source.setId(source_id);
346 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
347 source.setAccessorCount(key->totkey - 1);
348 source.setAccessorStride(1);
349
350 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
351 param.push_back("MORPH_WEIGHT");
352
353 source.prepareToAppendValues();
354
355 KeyBlock *kb = (KeyBlock *)key->block.first;
356 /* skip the basis */
357 kb = kb->next;
358 for (; kb; kb = kb->next) {
359 float weight = kb->curval;
360 source.appendValues(weight);
361 }
362 source.finish();
363
364 return source_id;
365}
366
367void ControllerExporter::add_weight_extras(Key *key)
368{
369 /* can also try the base element and param alternative */
370 COLLADASW::BaseExtraTechnique extra;
371
372 KeyBlock *kb = (KeyBlock *)key->block.first;
373 /* skip the basis */
374 kb = kb->next;
375 for (; kb; kb = kb->next) {
376 /* XXX why is the weight not used here and set to 0.0?
377 * float weight = kb->curval; */
378 extra.addExtraTechniqueParameter("KHR", "morph_weights", 0.000, "MORPH_WEIGHT_TO_TARGET");
379 }
380}
381
382void ControllerExporter::add_joints_element(const ListBase *defbase,
383 const std::string &joints_source_id,
384 const std::string &inv_bind_mat_source_id)
385{
386 COLLADASW::JointsElement joints(mSW);
387 COLLADASW::InputList &input = joints.getInputList();
388
389 input.push_back(COLLADASW::Input(
390 COLLADASW::InputSemantic::JOINT, /* constant declared in COLLADASWInputList.h */
391 COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, joints_source_id)));
392 input.push_back(
393 COLLADASW::Input(COLLADASW::InputSemantic::BINDMATRIX,
394 COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, inv_bind_mat_source_id)));
395 joints.add();
396}
397
398void ControllerExporter::add_bind_shape_mat(Object *ob)
399{
400 double bind_mat[4][4];
401 float f_obmat[4][4];
402 BKE_object_matrix_local_get(ob, f_obmat);
403
404 if (export_settings.get_apply_global_orientation()) {
405 /* do nothing, rotation is going to be applied to the Data */
406 }
407 else {
408 bc_add_global_transform(f_obmat, export_settings.get_global_transform());
409 }
410
411 // UnitConverter::mat4_to_dae_double(bind_mat, ob->object_to_world().ptr());
412 UnitConverter::mat4_to_dae_double(bind_mat, f_obmat);
413 if (this->export_settings.get_limit_precision()) {
415 }
416
417 addBindShapeTransform(bind_mat);
418}
419
420std::string ControllerExporter::add_joints_source(Object *ob_arm,
421 const ListBase *defbase,
422 const std::string &controller_id)
423{
424 std::string source_id = controller_id + JOINTS_SOURCE_ID_SUFFIX;
425
426 int totjoint = 0;
427 LISTBASE_FOREACH (bDeformGroup *, def, defbase) {
428 if (is_bone_defgroup(ob_arm, def)) {
429 totjoint++;
430 }
431 }
432
433 COLLADASW::NameSource source(mSW);
434 source.setId(source_id);
435 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
436 source.setAccessorCount(totjoint);
437 source.setAccessorStride(1);
438
439 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
440 param.push_back("JOINT");
441
442 source.prepareToAppendValues();
443
444 LISTBASE_FOREACH (bDeformGroup *, def, defbase) {
445 Bone *bone = get_bone_from_defgroup(ob_arm, def);
446 if (bone) {
447 source.appendValues(get_joint_sid(bone));
448 }
449 }
450
451 source.finish();
452
453 return source_id;
454}
455
456std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm,
457 const ListBase *defbase,
458 const std::string &controller_id)
459{
460 std::string source_id = controller_id + BIND_POSES_SOURCE_ID_SUFFIX;
461
462 int totjoint = 0;
463 LISTBASE_FOREACH (bDeformGroup *, def, defbase) {
464 if (is_bone_defgroup(ob_arm, def)) {
465 totjoint++;
466 }
467 }
468
469 COLLADASW::FloatSourceF source(mSW);
470 source.setId(source_id);
471 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
472 source.setAccessorCount(totjoint); // BLI_listbase_count(defbase));
473 source.setAccessorStride(16);
474
475 source.setParameterTypeName(&COLLADASW::CSWC::CSW_VALUE_TYPE_FLOAT4x4);
476 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
477 param.push_back("TRANSFORM");
478
479 source.prepareToAppendValues();
480
481 bPose *pose = ob_arm->pose;
482 bArmature *arm = (bArmature *)ob_arm->data;
483
484 int flag = arm->flag;
485
486 /* put armature in rest position */
487 if (!(arm->flag & ARM_RESTPOS)) {
488 Depsgraph *depsgraph = blender_context.get_depsgraph();
489 Scene *scene = blender_context.get_scene();
490
491 arm->flag |= ARM_RESTPOS;
492 BKE_pose_where_is(depsgraph, scene, ob_arm);
493 }
494
495 LISTBASE_FOREACH (bDeformGroup *, def, defbase) {
496 if (is_bone_defgroup(ob_arm, def)) {
497 bPoseChannel *pchan = BKE_pose_channel_find_name(pose, def->name);
498
499 float mat[4][4];
500 float world[4][4];
501 float inv_bind_mat[4][4];
502
503 float bind_mat[4][4]; /* derived from bone->arm_mat */
504
505 bool has_bindmat = bc_get_property_matrix(pchan->bone, "bind_mat", bind_mat);
506
507 if (!has_bindmat) {
508
509 /* Have no bind matrix stored, try old style <= Blender 2.78 */
510
512 this->export_settings, pchan->bone, bind_mat, pchan->bone->arm_mat, true);
513
514 /* SL/OPEN_SIM COMPATIBILITY */
515 if (export_settings.get_open_sim()) {
516 float loc[3];
517 float rot[3] = {0, 0, 0};
518 float scale[3];
519 bc_decompose(bind_mat, loc, nullptr, nullptr, scale);
520
521 /* Only translations, no rotation vs armature */
522 loc_eulO_size_to_mat4(bind_mat, loc, rot, scale, 6);
523 }
524 }
525
526 /* make world-space matrix (bind_mat is armature-space) */
527 mul_m4_m4m4(world, ob_arm->object_to_world().ptr(), bind_mat);
528
529 if (!has_bindmat) {
530 if (export_settings.get_apply_global_orientation()) {
531 bc_apply_global_transform(world, export_settings.get_global_transform());
532 }
533 }
534
535 invert_m4_m4(mat, world);
536 UnitConverter::mat4_to_dae(inv_bind_mat, mat);
537 if (this->export_settings.get_limit_precision()) {
539 }
540 source.appendValues(inv_bind_mat);
541 }
542 }
543
544 /* back from rest position */
545 if (!(flag & ARM_RESTPOS)) {
546 Depsgraph *depsgraph = blender_context.get_depsgraph();
547 Scene *scene = blender_context.get_scene();
548 arm->flag = flag;
549 BKE_pose_where_is(depsgraph, scene, ob_arm);
550 }
551
552 source.finish();
553
554 return source_id;
555}
556
557Bone *ControllerExporter::get_bone_from_defgroup(Object *ob_arm, const bDeformGroup *def)
558{
559 bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, def->name);
560 return pchan ? pchan->bone : nullptr;
561}
562
563bool ControllerExporter::is_bone_defgroup(Object *ob_arm, const bDeformGroup *def)
564{
565 return get_bone_from_defgroup(ob_arm, def) != nullptr;
566}
567
568std::string ControllerExporter::add_weights_source(Mesh *mesh,
569 const std::string &controller_id,
570 const std::list<float> &weights)
571{
572 std::string source_id = controller_id + WEIGHTS_SOURCE_ID_SUFFIX;
573
574 COLLADASW::FloatSourceF source(mSW);
575 source.setId(source_id);
576 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
577 source.setAccessorCount(weights.size());
578 source.setAccessorStride(1);
579
580 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
581 param.push_back("WEIGHT");
582
583 source.prepareToAppendValues();
584
585 for (float weight : weights) {
586 source.appendValues(weight);
587 }
588
589 source.finish();
590
591 return source_id;
592}
593
594void ControllerExporter::add_vertex_weights_element(const std::string &weights_source_id,
595 const std::string &joints_source_id,
596 const std::list<int> &vcounts,
597 const std::list<int> &joints)
598{
599 COLLADASW::VertexWeightsElement weightselem(mSW);
600 COLLADASW::InputList &input = weightselem.getInputList();
601
602 int offset = 0;
603 input.push_back(COLLADASW::Input(
604 COLLADASW::InputSemantic::JOINT, /* constant declared in COLLADASWInputList.h */
605 COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, joints_source_id),
606 offset++));
607 input.push_back(
608 COLLADASW::Input(COLLADASW::InputSemantic::WEIGHT,
609 COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, weights_source_id),
610 offset++));
611
612 weightselem.setCount(vcounts.size());
613
614 /* write number of deformers per vertex */
615 COLLADASW::PrimitivesBase::VCountList vcountlist;
616
617 vcountlist.resize(vcounts.size());
618 std::copy(vcounts.begin(), vcounts.end(), vcountlist.begin());
619
620 weightselem.prepareToAppendVCountValues();
621 weightselem.appendVertexCount(vcountlist);
622
623 weightselem.CloseVCountAndOpenVElement();
624
625 /* write deformer index - weight index pairs */
626 int weight_index = 0;
627 for (int joint_index : joints) {
628 weightselem.appendValues(joint_index, weight_index++);
629 }
630
631 weightselem.finish();
632}
Blender kernel action and pose functionality.
bPoseChannel * BKE_pose_channel_find_name(const bPose *pose, const char *name)
void BKE_pose_where_is(Depsgraph *depsgraph, Scene *scene, Object *ob)
Definition armature.cc:2941
support for deformation groups and hooks.
const ListBase * BKE_object_defgroup_list(const Object *ob)
Definition deform.cc:579
Key * BKE_key_from_object(Object *ob)
Definition key.cc:1820
void BKE_id_free(Main *bmain, void *idv)
void BKE_object_matrix_local_get(Object *ob, float r_mat[4][4])
#define LISTBASE_FOREACH(type, var, list)
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void loc_eulO_size_to_mat4(float R[4][4], const float loc[3], const float eul[3], const float size[3], short order)
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
unsigned int uint
@ ARM_RESTPOS
@ OB_MESH
static void sanitize(Matrix &matrix, int precision)
Definition BCMath.cpp:142
bool add_instance_controller(Object *ob)
void operator()(Object *ob)
bool is_skinned_mesh(Object *ob)
void add_material_bindings(COLLADASW::BindMaterial &bind_material, Object *ob, bool active_uv_only)
static void mat4_to_dae(float out[4][4], float in[4][4])
static void mat4_to_dae_double(double out[4][4], float in[4][4])
std::string get_joint_sid(Bone *bone)
std::string translate_id(const char *idString)
std::string get_geometry_id(Object *ob)
std::string id_name(void *id)
bool bc_is_root_bone(Bone *aBone, bool deform_bones_only)
void bc_add_global_transform(Matrix &to_mat, const Matrix &from_mat, const BCMatrix &global_transform, const bool invert)
void bc_apply_global_transform(Matrix &to_mat, const BCMatrix &global_transform, const bool invert)
Object * bc_get_assigned_armature(Object *ob)
void bc_create_restpose_mat(BCExportSettings &export_settings, Bone *bone, float to_mat[4][4], float from_mat[4][4], bool use_local_space)
Mesh * bc_get_mesh_copy(BlenderContext &blender_context, Object *ob, BC_export_mesh_type export_mesh_type, bool apply_modifiers, bool triangulate)
bool bc_get_property_matrix(Bone *bone, std::string key, float mat[4][4])
void bc_decompose(float mat[4][4], float *loc, float eul[3], float quat[4], float *size)
constexpr int LIMITTED_PRECISION
const Depsgraph * depsgraph
#define rot(x, k)
char name[64]
float arm_mat[4][4]
ListBase childbase
void forEachMeshObjectInExportSet(Scene *sce, Functor &f, LinkNode *export_set)
int totkey
ListBase block
void * first
struct MDeformWeight * dw
unsigned int def_nr
struct bPose * pose
struct bDeformGroup * next
struct Bone * bone
uint8_t flag
Definition wm_window.cc:138