Blender V4.5
fbx_import_anim.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <algorithm>
10
11#include "ANIM_action.hh"
12#include "ANIM_animdata.hh"
13
14#include "BKE_action.hh"
15#include "BKE_fcurve.hh"
16#include "BKE_lib_id.hh"
17#include "BKE_object_types.hh"
18
20#include "BLI_map.hh"
23#include "BLI_set.hh"
24#include "BLI_string.h"
25#include "BLI_vector.hh"
26#include "BLI_vector_set.hh"
27
28#include "DNA_key_types.h"
29#include "DNA_material_types.h"
30
31#include "fbx_import_anim.hh"
32#include "fbx_import_util.hh"
33
34namespace blender::io::fbx {
35
38 int64_t key_count)
39{
40 FCurve *cu = channelbag.fcurve_create_unique(nullptr, descriptor);
41 BLI_assert_msg(cu, "The same F-Curve is being created twice, this is unexpected.");
42 BKE_fcurve_bezt_resize(cu, key_count);
43 return cu;
44}
45
46static void set_curve_sample(FCurve *curve, int64_t key_index, float time, float value)
47{
48 BLI_assert(key_index >= 0 && key_index < curve->totvert);
49 BezTriple &bez = curve->bezt[key_index];
50 bez.vec[1][0] = time;
51 bez.vec[1][1] = value;
52 bez.ipo = BEZT_IPO_LIN;
53 bez.f1 = bez.f2 = bez.f3 = SELECT;
54 bez.h1 = bez.h2 = HD_AUTO_ANIM;
55}
56
58 const ufbx_element *fbx_elem = nullptr;
59 ID *target_id = nullptr;
62 const ufbx_anim_prop *prop_position = nullptr;
63 const ufbx_anim_prop *prop_rotation = nullptr;
64 const ufbx_anim_prop *prop_scale = nullptr;
65 const ufbx_anim_prop *prop_blend_shape = nullptr;
66 const ufbx_anim_prop *prop_focal_length = nullptr;
67 const ufbx_anim_prop *prop_focus_dist = nullptr;
68 const ufbx_anim_prop *prop_mat_diffuse = nullptr;
69};
70
72 const ufbx_anim_layer &flayer)
73{
74 int64_t order = 0;
76 for (const ufbx_anim_prop &fprop : flayer.anim_props) {
77 if (fprop.anim_value->curves[0] == nullptr) {
78 continue;
79 }
80 bool supported_prop = false;
81 //@TODO: "Visibility"?
82 const bool is_position = STREQ(fprop.prop_name.data, "Lcl Translation");
83 const bool is_rotation = STREQ(fprop.prop_name.data, "Lcl Rotation");
84 const bool is_scale = STREQ(fprop.prop_name.data, "Lcl Scaling");
85 const bool is_blend_shape = STREQ(fprop.prop_name.data, "DeformPercent");
86 const bool is_focal_length = STREQ(fprop.prop_name.data, "FocalLength");
87 const bool is_focus_dist = STREQ(fprop.prop_name.data, "FocusDistance");
88 const bool is_diffuse = STREQ(fprop.prop_name.data, "DiffuseColor");
89 if (is_position || is_rotation || is_scale || is_blend_shape || is_focal_length ||
90 is_focus_dist || is_diffuse)
91 {
92 supported_prop = true;
93 }
94
95 if (!supported_prop) {
96 continue;
97 }
98
99 const bool is_anim_camera = is_focal_length || is_focus_dist;
100 const bool is_anim_mat = is_diffuse;
101
102 ID *target_id = nullptr;
103 eRotationModes object_rotmode = ROT_MODE_QUAT;
104
105 if (is_blend_shape) {
106 /* Animating blend shape weight. */
107 Key *target_key = mapping.el_to_shape_key.lookup_default(fprop.element, nullptr);
108 if (target_key != nullptr) {
109 target_id = &target_key->id;
110 }
111 }
112 else if (is_anim_camera) {
113 /* Animating camera property. */
114 if (fprop.element->instances.count > 0) {
115 Object *obj = mapping.el_to_object.lookup_default(&fprop.element->instances[0]->element,
116 nullptr);
117 if (obj != nullptr && obj->type == OB_CAMERA) {
118 target_id = (ID *)obj->data;
119 object_rotmode = static_cast<eRotationModes>(obj->rotmode);
120 }
121 }
122 }
123 else if (is_anim_mat) {
124 /* Animating material property. */
125 Material *mat = mapping.mat_to_material.lookup_default((ufbx_material *)fprop.element,
126 nullptr);
127 if (mat != nullptr) {
128 target_id = (ID *)mat;
129 }
130 }
131 else {
132 /* Animating Bone/Armature/Object property. */
133 const ufbx_node *fnode = ufbx_as_node(fprop.element);
134 Object *obj = nullptr;
135 if (fnode) {
136 obj = mapping.bone_to_armature.lookup_default(fnode, nullptr);
137 }
138 if (obj == nullptr) {
139 obj = mapping.el_to_object.lookup_default(fprop.element, nullptr);
140 }
141 if (obj == nullptr) {
142 continue;
143 }
144 /* Ignore animation of rigged meshes (very hard to handle; matches behavior of python fbx
145 * importer). */
146 if (obj->type == OB_MESH && obj->parent && obj->parent->type == OB_ARMATURE) {
147 continue;
148 }
149 target_id = &obj->id;
150 object_rotmode = static_cast<eRotationModes>(obj->rotmode);
151 }
152
153 if (target_id == nullptr) {
154 continue;
155 }
156
157 ElementAnimations &anims = elem_map.lookup_or_add_default(fprop.element);
158 anims.fbx_elem = fprop.element;
159 anims.order = order++;
160 anims.target_id = target_id;
161 anims.object_rotmode = object_rotmode;
162
163 if (is_position) {
164 anims.prop_position = &fprop;
165 }
166 if (is_rotation) {
167 anims.prop_rotation = &fprop;
168 }
169 if (is_scale) {
170 anims.prop_scale = &fprop;
171 }
172 if (is_blend_shape) {
173 anims.prop_blend_shape = &fprop;
174 }
175 if (is_focal_length) {
176 anims.prop_focal_length = &fprop;
177 }
178 if (is_focus_dist) {
179 anims.prop_focus_dist = &fprop;
180 }
181 if (is_diffuse) {
182 anims.prop_mat_diffuse = &fprop;
183 }
184 }
185
186 /* Sort returned result in the original fbx file order. */
187 Vector<ElementAnimations> animations(elem_map.values().begin(), elem_map.values().end());
188 std::sort(
189 animations.begin(),
190 animations.end(),
191 [](const ElementAnimations &a, const ElementAnimations &b) { return a.order < b.order; });
192 return animations;
193}
194
195static void finalize_curve(FCurve *cu)
196{
197 if (cu != nullptr) {
199 }
200}
201
203 const ElementAnimations &anim,
204 LinearAllocator<> &curve_name_alloc,
206{
207 /* For animated bones, prepend bone path to animation curve path. */
208 std::string rna_prefix;
209 std::string group_name_str = get_fbx_name(anim.fbx_elem->name);
210 const ufbx_node *fnode = ufbx_as_node(anim.fbx_elem);
211 const bool is_bone = mapping.node_is_blender_bone.contains(fnode);
212 if (is_bone) {
213 group_name_str = mapping.node_to_name.lookup_default(fnode, "");
214 rna_prefix = std::string("pose.bones[\"") + group_name_str + "\"].";
215 }
216
217 StringRefNull group_name = curve_name_alloc.copy_string(group_name_str);
218
219 StringRefNull rna_position = curve_name_alloc.copy_string(rna_prefix + "location");
220
221 StringRefNull rna_rotation;
222 int rot_channels = 3;
223 /* Bones are created with quaternion rotation. */
224 eRotationModes rot_mode = is_bone ? ROT_MODE_QUAT : anim.object_rotmode;
225 switch (rot_mode) {
226 case ROT_MODE_QUAT:
227 rna_rotation = curve_name_alloc.copy_string(rna_prefix + "rotation_quaternion");
228 rot_channels = 4;
229 break;
231 rna_rotation = curve_name_alloc.copy_string(rna_prefix + "rotation_axis_angle");
232 rot_channels = 4;
233 break;
234 default:
235 rna_rotation = curve_name_alloc.copy_string(rna_prefix + "rotation_euler");
236 rot_channels = 3;
237 break;
238 }
239
240 StringRefNull rna_scale = curve_name_alloc.copy_string(rna_prefix + "scale");
241
242 /* Fill the f-curve descriptors. */
243 for (int i = 0; i < 3; i++) {
244 r_curve_desc.append({rna_position, i, {}, {}, group_name});
245 }
246 for (int i = 0; i < rot_channels; i++) {
247 r_curve_desc.append({rna_rotation, i, {}, {}, group_name});
248 }
249 for (int i = 0; i < 3; i++) {
250 r_curve_desc.append({rna_scale, i, {}, {}, group_name});
251 }
252}
253
255 const ufbx_anim *fbx_anim,
256 const ElementAnimations &anim,
257 const double fps,
258 const float anim_offset,
259 FCurve **curves)
260{
261 const ufbx_node *fnode = ufbx_as_node(anim.fbx_elem);
262 ufbx_matrix bone_xform = ufbx_identity_matrix;
263 const bool is_bone = mapping.node_is_blender_bone.contains(fnode);
264 if (is_bone) {
265 /* Bone transform curves need to be transformed to the bind transform
266 * in joint-local space:
267 * - Calculate local space bind matrix: inv(parent_bind) * bind
268 * - Invert the result; this will be used to transform loc/rot/scale curves. */
269
270 const bool bone_at_scene_root = fnode->node_depth <= 1;
271 ufbx_matrix world_to_arm = ufbx_identity_matrix;
272 if (!bone_at_scene_root) {
273 Object *arm_obj = mapping.bone_to_armature.lookup_default(fnode, nullptr);
274 if (arm_obj != nullptr) {
276 arm_obj, ufbx_identity_matrix);
277 }
278 }
279
280 bone_xform = mapping.calc_local_bind_matrix(fnode, world_to_arm);
281 bone_xform = ufbx_matrix_invert(&bone_xform);
282 }
283
284 int rot_channels = 3;
285 /* Bones are created with quaternion rotation. */
286 eRotationModes rot_mode = is_bone ? ROT_MODE_QUAT : anim.object_rotmode;
287 switch (rot_mode) {
288 case ROT_MODE_QUAT:
289 rot_channels = 4;
290 break;
292 rot_channels = 4;
293 break;
294 default:
295 rot_channels = 3;
296 break;
297 }
298
299 /* Note: Python importer was always creating all pos/rot/scale curves: "due to all FBX
300 * transform magic, we need to add curves for whole loc/rot/scale in any case".
301 *
302 * Also, we create a full transform keyframe at any point where input pos/rot/scale curves have
303 * a keyframe. It should not be needed if we fully imported curves with all their proper
304 * handles, but again currently this is to match Python importer behavior. */
305 const ufbx_anim_curve *input_curves[9] = {};
306 if (anim.prop_position) {
307 input_curves[0] = anim.prop_position->anim_value->curves[0];
308 input_curves[1] = anim.prop_position->anim_value->curves[1];
309 input_curves[2] = anim.prop_position->anim_value->curves[2];
310 }
311 if (anim.prop_rotation) {
312 input_curves[3] = anim.prop_rotation->anim_value->curves[0];
313 input_curves[4] = anim.prop_rotation->anim_value->curves[1];
314 input_curves[5] = anim.prop_rotation->anim_value->curves[2];
315 }
316 if (anim.prop_scale) {
317 input_curves[6] = anim.prop_scale->anim_value->curves[0];
318 input_curves[7] = anim.prop_scale->anim_value->curves[1];
319 input_curves[8] = anim.prop_scale->anim_value->curves[2];
320 }
321
322 /* Figure out timestamps of where any of input curves have a keyframe. */
323 Set<double> unique_key_times;
324 for (int i = 0; i < 9; i++) {
325 if (input_curves[i] != nullptr) {
326 for (const ufbx_keyframe &key : input_curves[i]->keyframes) {
327 if (key.interpolation == UFBX_INTERPOLATION_CUBIC) {
328 /* Hack: force cubic keyframes to be linear, to match Python importer behavior. */
329 const_cast<ufbx_keyframe &>(key).interpolation = UFBX_INTERPOLATION_LINEAR;
330 }
331 unique_key_times.add(key.time);
332 }
333 }
334 }
335 Vector<double> sorted_key_times(unique_key_times.begin(), unique_key_times.end());
336 std::sort(sorted_key_times.begin(), sorted_key_times.end());
337
338 int64_t pos_index = 0;
339 int64_t rot_index = pos_index + 3;
340 int64_t scale_index = rot_index + rot_channels;
341 int64_t tot_curves = scale_index + 3;
342 for (int64_t i = 0; i < tot_curves; i++) {
343 BLI_assert_msg(curves[i], "fbx: animation curve was not created successfully");
344 BKE_fcurve_bezt_resize(curves[i], sorted_key_times.size());
345 }
346
347 /* Evaluate transforms at all the key times. */
349 for (int64_t i = 0; i < sorted_key_times.size(); i++) {
350 double t = sorted_key_times[i];
351 float tf = float(t * fps + anim_offset);
352 ufbx_transform xform = ufbx_evaluate_transform(fbx_anim, fnode, t);
353
354 if (is_bone) {
355 ufbx_matrix matrix = calc_bone_pose_matrix(xform, *fnode, bone_xform);
356 xform = ufbx_matrix_to_transform(&matrix);
357 }
358
359 set_curve_sample(curves[pos_index + 0], i, tf, float(xform.translation.x));
360 set_curve_sample(curves[pos_index + 1], i, tf, float(xform.translation.y));
361 set_curve_sample(curves[pos_index + 2], i, tf, float(xform.translation.z));
362
363 math::Quaternion quat(xform.rotation.w, xform.rotation.x, xform.rotation.y, xform.rotation.z);
364 switch (rot_mode) {
365 case ROT_MODE_QUAT:
366 /* Ensure shortest interpolation path between consecutive quaternions. */
367 if (i != 0 && math::dot(quat, quat_prev) < 0.0f) {
368 quat = -quat;
369 }
370 quat_prev = quat;
371 set_curve_sample(curves[rot_index + 0], i, tf, quat.w);
372 set_curve_sample(curves[rot_index + 1], i, tf, quat.x);
373 set_curve_sample(curves[rot_index + 2], i, tf, quat.y);
374 set_curve_sample(curves[rot_index + 3], i, tf, quat.z);
375 break;
376 case ROT_MODE_AXISANGLE: {
377 const math::AxisAngle axis_angle = math::to_axis_angle(quat);
378 set_curve_sample(curves[rot_index + 0], i, tf, axis_angle.angle().radian());
379 set_curve_sample(curves[rot_index + 1], i, tf, axis_angle.axis().x);
380 set_curve_sample(curves[rot_index + 2], i, tf, axis_angle.axis().y);
381 set_curve_sample(curves[rot_index + 3], i, tf, axis_angle.axis().z);
382 } break;
383 default: {
384 math::EulerXYZ euler = math::to_euler(quat);
385 set_curve_sample(curves[rot_index + 0], i, tf, euler.x().radian());
386 set_curve_sample(curves[rot_index + 1], i, tf, euler.y().radian());
387 set_curve_sample(curves[rot_index + 2], i, tf, euler.z().radian());
388 } break;
389 }
390
391 set_curve_sample(curves[scale_index + 0], i, tf, float(xform.scale.x));
392 set_curve_sample(curves[scale_index + 1], i, tf, float(xform.scale.y));
393 set_curve_sample(curves[scale_index + 2], i, tf, float(xform.scale.z));
394 }
395}
396
397static void create_camera_curves(const ufbx_metadata &metadata,
398 const ElementAnimations &anim,
399 animrig::Channelbag &channelbag,
400 const double fps,
401 const float anim_offset)
402{
403 if (anim.target_id == nullptr || GS(anim.target_id->name) != ID_CA) {
404 return;
405 }
406
407 if (anim.prop_focal_length != nullptr) {
408 const ufbx_anim_curve *input_curve = anim.prop_focal_length->anim_value->curves[0];
409 FCurve *curve = create_fcurve(channelbag, {"lens", 0}, input_curve->keyframes.count);
410 for (int i = 0; i < input_curve->keyframes.count; i++) {
411 const ufbx_keyframe &fkey = input_curve->keyframes[i];
412 float tf = float(fkey.time * fps + anim_offset);
413 float val = float(fkey.value);
414 set_curve_sample(curve, i, tf, val);
415 }
416 finalize_curve(curve);
417 }
418
419 if (anim.prop_focus_dist != nullptr) {
420 const ufbx_anim_curve *input_curve = anim.prop_focus_dist->anim_value->curves[0];
421 FCurve *curve = create_fcurve(
422 channelbag, {"dof.focus_distance", 0}, input_curve->keyframes.count);
423 for (int i = 0; i < input_curve->keyframes.count; i++) {
424 const ufbx_keyframe &fkey = input_curve->keyframes[i];
425 float tf = float(fkey.time * fps + anim_offset);
426 /* Animation curves containing camera focus distance have values multiplied by 1000.0 */
427 float val = float(fkey.value / 1000.0 * metadata.geometry_scale * metadata.root_scale);
428 set_curve_sample(curve, i, tf, val);
429 }
430 finalize_curve(curve);
431 }
432}
433
435 bAction *action,
436 animrig::Channelbag &channelbag,
437 const double fps,
438 const float anim_offset)
439{
440 if (anim.target_id == nullptr || GS(anim.target_id->name) != ID_MA) {
441 return;
442 }
443
444 const char *rna_path_1 = "diffuse_color";
445 const char *rna_path_2 = "nodes[\"Principled BSDF\"].inputs[0].default_value";
446
447 /* Also create animation curves for the node tree diffuse color input. */
448 Material *target_mat = (Material *)anim.target_id;
449 ID *target_ntree = (ID *)target_mat->nodetree;
450 animrig::Action &act = action->wrap();
451 const animrig::Slot *slot = animrig::assign_action_ensure_slot_for_keying(act, *target_ntree);
452 BLI_assert(slot != nullptr);
453 UNUSED_VARS_NDEBUG(slot);
454 animrig::Channelbag &chbag_node = animrig::action_channelbag_ensure(*action, *target_ntree);
455
456 if (anim.prop_mat_diffuse != nullptr) {
457 for (int ch = 0; ch < 3; ch++) {
458 const ufbx_anim_curve *input_curve = anim.prop_mat_diffuse->anim_value->curves[ch];
459 FCurve *curve_1 = create_fcurve(channelbag, {rna_path_1, ch}, input_curve->keyframes.count);
460 FCurve *curve_2 = create_fcurve(chbag_node, {rna_path_2, ch}, input_curve->keyframes.count);
461 for (int i = 0; i < input_curve->keyframes.count; i++) {
462 const ufbx_keyframe &fkey = input_curve->keyframes[i];
463 float tf = float(fkey.time * fps + anim_offset);
464 float val = float(fkey.value);
465 set_curve_sample(curve_1, i, tf, val);
466 set_curve_sample(curve_2, i, tf, val);
467 }
468 finalize_curve(curve_1);
469 finalize_curve(curve_2);
470 }
471 }
472}
473
475 animrig::Channelbag &channelbag,
476 const double fps,
477 const float anim_offset)
478{
479 const ufbx_blend_channel *fchan = ufbx_as_blend_channel(anim.prop_blend_shape->element);
480 BLI_assert(fchan != nullptr);
481 std::string rna_path = std::string("key_blocks[\"") + fchan->target_shape->name.data +
482 "\"].value";
483 const ufbx_anim_curve *input_curve = anim.prop_blend_shape->anim_value->curves[0];
484 FCurve *curve = create_fcurve(channelbag, {rna_path, 0}, input_curve->keyframes.count);
485 for (int i = 0; i < input_curve->keyframes.count; i++) {
486 const ufbx_keyframe &fkey = input_curve->keyframes[i];
487 double t = fkey.time;
488 float tf = float(t * fps + anim_offset);
489 float val = float(fkey.value / 100.0); /* FBX shape weights are 0..100 range. */
490 set_curve_sample(curve, i, tf, val);
491 }
492 finalize_curve(curve);
493}
494
496 const ufbx_scene &fbx,
497 const FbxElementMapping &mapping,
498 const double fps,
499 const float anim_offset)
500{
501 /* Note: mixing is completely ignored for now, each layer results in an independent set of
502 * actions. */
503 for (const ufbx_anim_stack *fstack : fbx.anim_stacks) {
504 for (const ufbx_anim_layer *flayer : fstack->layers) {
505 Vector<ElementAnimations> animations = gather_animated_properties(mapping, *flayer);
506 if (animations.is_empty()) {
507 continue;
508 }
509
510 /* Create action for this layer. */
511 std::string action_name = fstack->name.data;
512 if (!STREQ(fstack->name.data, flayer->name.data) && fstack->layers.count != 1) {
513 action_name += '|';
514 action_name += flayer->name.data;
515 }
516 animrig::Action &action = animrig::action_add(bmain, action_name);
517 id_fake_user_set(&action.id);
518 action.layer_keystrip_ensure();
519 animrig::StripKeyframeData &strip_data =
520 action.layer(0)->strip(0)->data<animrig::StripKeyframeData>(action);
521
522 /* Figure out the set of IDs that are animated. We want to preserve the order
523 * of this set to match order of animations inside the FBX file. */
524 VectorSet<ID *> animated_ids;
526 for (const ElementAnimations &anim : animations) {
527 animated_ids.add(anim.target_id);
529 anim.target_id);
530 anims.append(&anim);
531 }
532
533 /* Create action slots for each animated ID. */
534 for (ID *id : animated_ids) {
535 /* Create a slot for this ID. */
536 BLI_assert(id != nullptr);
537 const std::string slot_name = id->name;
538 animrig::Slot &slot = action.slot_add_for_id_type(GS(id->name));
539 action.slot_identifier_define(slot, slot_name);
540
541 /* Assign this action & slot to ID. */
542 const AnimData *adt = BKE_animdata_ensure_id(id);
543 BLI_assert_msg(adt != nullptr, "fbx: could not create animation data for an ID");
544 if (adt->action == nullptr) {
545 bool ok = animrig::assign_action(&action, *id);
546 BLI_assert_msg(ok, "fbx: could not assign action to ID");
548 }
552 "fbx: failed to assign slot to ID");
554 }
555 animrig::Channelbag &channelbag = strip_data.channelbag_for_slot_ensure(slot);
556
557 /* Create animation curves for this ID. */
558 Vector<const ElementAnimations *> id_anims = id_to_anims.lookup(id);
559 /* Batch create the transform curves: creating them one by one is not very fast,
560 * especially for armatures where many bones often are animated. So first create
561 * their descriptors, then create the f-curves in one step, and finally fill their data. */
563 Vector<int64_t> anim_transform_curve_index(id_anims.size());
564 LinearAllocator name_alloc;
565 for (const int64_t index : id_anims.index_range()) {
566 const ElementAnimations *anim = id_anims[index];
567 if (anim->prop_position || anim->prop_rotation || anim->prop_scale) {
568 anim_transform_curve_index[index] = curve_desc.size();
569 create_transform_curve_desc(mapping, *anim, name_alloc, curve_desc);
570 }
571 else {
572 anim_transform_curve_index[index] = -1;
573 }
574 }
575 blender::Vector<FCurve *> transform_curves;
576 if (!curve_desc.is_empty()) {
577 transform_curves = channelbag.fcurve_create_many(nullptr, curve_desc.as_span());
578 }
579
580 for (const int64_t index : id_anims.index_range()) {
581 const ElementAnimations *anim = id_anims[index];
582 if (anim->prop_position || anim->prop_rotation || anim->prop_scale) {
584 flayer->anim,
585 *anim,
586 fps,
587 anim_offset,
588 transform_curves.data() +
589 anim_transform_curve_index[index]);
590 }
591 if (anim->prop_focal_length || anim->prop_focus_dist) {
592 create_camera_curves(fbx.metadata, *anim, channelbag, fps, anim_offset);
593 }
594 if (anim->prop_mat_diffuse) {
595 create_material_curves(*anim, &action, channelbag, fps, anim_offset);
596 }
597 if (anim->prop_blend_shape) {
598 create_blend_shape_curves(*anim, channelbag, fps, anim_offset);
599 }
600 }
601
602 for (FCurve *curve : transform_curves) {
603 finalize_curve(curve);
604 }
605 }
606 }
607 }
608}
609
610} // namespace blender::io::fbx
Functions and classes to work with Actions.
Functions to work with AnimData.
Blender kernel action and pose functionality.
AnimData * BKE_animdata_ensure_id(ID *id)
Definition anim_data.cc:96
void BKE_fcurve_handles_recalc(FCurve *fcu)
void BKE_fcurve_bezt_resize(FCurve *fcu, int new_totvert)
void id_fake_user_set(ID *id)
Definition lib_id.cc:391
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define UNUSED_VARS_NDEBUG(...)
#define STREQ(a, b)
@ ID_CA
@ ID_MA
eRotationModes
@ ROT_MODE_QUAT
@ ROT_MODE_AXISANGLE
@ HD_AUTO_ANIM
@ BEZT_IPO_LIN
@ OB_CAMERA
@ OB_ARMATURE
@ OB_MESH
long long int int64_t
SubIterator begin() const
Definition BLI_map.hh:768
SubIterator end() const
Definition BLI_map.hh:778
Value lookup_default(const Key &key, const Value &default_value) const
Definition BLI_map.hh:570
bool contains(const Key &key) const
Definition BLI_set.hh:310
StringRefNull copy_string(StringRef str)
Value & lookup_or_add_default(const Key &key)
Definition BLI_map.hh:639
ValueIterator values() const &
Definition BLI_map.hh:884
const Value & lookup(const Key &key) const
Definition BLI_map.hh:545
Iterator begin() const
Definition BLI_set.hh:480
Iterator end() const
Definition BLI_set.hh:490
bool add(const Key &key)
Definition BLI_set.hh:248
int64_t size() const
void append(const T &value)
bool is_empty() const
IndexRange index_range() const
Span< T > as_span() const
const Layer * layer(int64_t index) const
Slot & slot_add_for_id_type(ID_Type idtype)
void slot_identifier_define(Slot &slot, StringRefNull new_identifier)
Vector< FCurve * > fcurve_create_many(Main *bmain, Span< FCurveDescriptor > fcurve_descriptors)
FCurve * fcurve_create_unique(Main *bmain, const FCurveDescriptor &fcurve_descriptor)
const Strip * strip(int64_t index) const
static constexpr slot_handle_t unassigned
Channelbag & channelbag_for_slot_ensure(const Slot &slot)
const T & data(const Action &owning_action) const
#define SELECT
#define GS(a)
descriptor
Slot * assign_action_ensure_slot_for_keying(Action &action, ID &animated_id)
Action & action_add(Main &bmain, StringRefNull name)
Channelbag & action_channelbag_ensure(bAction &dna_action, ID &animated_id)
bool assign_action(bAction *action, ID &animated_id)
ActionSlotAssignmentResult assign_action_slot(Slot *slot_to_assign, ID &animated_id)
static void create_transform_curve_desc(const FbxElementMapping &mapping, const ElementAnimations &anim, LinearAllocator<> &curve_name_alloc, Vector< animrig::FCurveDescriptor > &r_curve_desc)
static void create_camera_curves(const ufbx_metadata &metadata, const ElementAnimations &anim, animrig::Channelbag &channelbag, const double fps, const float anim_offset)
const char * get_fbx_name(const ufbx_string &name, const char *def)
static void create_transform_curve_data(const FbxElementMapping &mapping, const ufbx_anim *fbx_anim, const ElementAnimations &anim, const double fps, const float anim_offset, FCurve **curves)
static void create_material_curves(const ElementAnimations &anim, bAction *action, animrig::Channelbag &channelbag, const double fps, const float anim_offset)
static void set_curve_sample(FCurve *curve, int64_t key_index, float time, float value)
static void finalize_curve(FCurve *cu)
static Vector< ElementAnimations > gather_animated_properties(const FbxElementMapping &mapping, const ufbx_anim_layer &flayer)
void import_animations(Main &bmain, const ufbx_scene &fbx, const FbxElementMapping &mapping, const double fps, const float anim_offset)
static FCurve * create_fcurve(animrig::Channelbag &channelbag, const animrig::FCurveDescriptor &descriptor, int64_t key_count)
ufbx_matrix calc_bone_pose_matrix(const ufbx_transform &local_xform, const ufbx_node &node, const ufbx_matrix &local_bind_inv_matrix)
static void create_blend_shape_curves(const ElementAnimations &anim, animrig::Channelbag &channelbag, const double fps, const float anim_offset)
QuaternionBase< float > Quaternion
AxisAngleBase< float, AngleRadianBase< float > > AxisAngle
EulerXYZBase< float > EulerXYZ
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
AxisAngleBase< T, AngleT > to_axis_angle(const EulerXYZBase< T > &euler)
Euler3Base< T > to_euler(const AxisAngleBase< T, AngleT > &axis_angle, EulerOrder order)
bAction * action
int32_t slot_handle
float vec[3][3]
BezTriple * bezt
Definition DNA_ID.h:404
char name[66]
Definition DNA_ID.h:415
struct bNodeTree * nodetree
const ufbx_anim_prop * prop_focal_length
const ufbx_anim_prop * prop_blend_shape
const ufbx_anim_prop * prop_mat_diffuse
const ufbx_anim_prop * prop_focus_dist
Map< const ufbx_node *, Object * > bone_to_armature
Map< const ufbx_material *, Material * > mat_to_material
Map< const ufbx_node *, std::string > node_to_name
Set< const ufbx_node * > node_is_blender_bone
Map< const Object *, ufbx_matrix > armature_world_to_arm_pose_matrix
ufbx_matrix calc_local_bind_matrix(const ufbx_node *bone_node, const ufbx_matrix &world_to_arm) const
Map< const ufbx_element *, Object * > el_to_object
Map< const ufbx_element *, Key * > el_to_shape_key
i
Definition text_draw.cc:230