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
8
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
struct bPoseChannel bPoseChannel
struct bPose bPose
struct Bone Bone
@ ARM_RESTPOS
struct bArmature bArmature
struct KeyBlock KeyBlock
struct Base Base
struct ListBase ListBase
struct Mesh Mesh
struct MDeformVert MDeformVert
@ OB_MESH
struct bDeformGroup bDeformGroup
struct Object Object
struct Scene Scene
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between world
BPy_StructRNA * depsgraph
static void sanitize(Matrix &matrix, int precision)
Definition BCMath.cpp:142
ControllerExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, BCExportSettings &export_settings)
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
#define rot(x, k)
MatBase< T, NumCol, NumRow > scale(const MatBase< T, NumCol, NumRow > &mat, const VectorT &scale)
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
int verts_num
struct bPose * pose
struct bDeformGroup * next
struct Bone * bone
uint8_t flag
Definition wm_window.cc:138