1/**************************************************************************/
2/* post_import_plugin_skeleton_rest_fixer.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#include "post_import_plugin_skeleton_rest_fixer.h"
32
33#include "editor/import/scene_import_settings.h"
34#include "scene/3d/bone_attachment_3d.h"
35#include "scene/3d/importer_mesh_instance_3d.h"
36#include "scene/3d/skeleton_3d.h"
37#include "scene/animation/animation_player.h"
38#include "scene/resources/bone_map.h"
39
40void PostImportPluginSkeletonRestFixer::get_internal_import_options(InternalImportCategory p_category, List<ResourceImporter::ImportOption> *r_options) {
41 if (p_category == INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE) {
42 r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/apply_node_transforms"), true));
43 r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/normalize_position_tracks"), true));
44 r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/overwrite_axis"), true));
45 r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/fix_silhouette/enable"), false));
46 // TODO: PostImportPlugin need to be implemented such as validate_option(PropertyInfo &property, const Dictionary &p_options).
47 // get_internal_option_visibility() is not sufficient because it can only retrieve options implemented in the core and can only read option values.
48 // r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::ARRAY, "retarget/rest_fixer/filter", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::STRING_NAME, PROPERTY_HINT_ENUM, "Hips,Spine,Chest")), Array()));
49 r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::ARRAY, "retarget/rest_fixer/fix_silhouette/filter", PROPERTY_HINT_ARRAY_TYPE, "StringName"), Array()));
50 r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::FLOAT, "retarget/rest_fixer/fix_silhouette/threshold"), 15));
51 r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::FLOAT, "retarget/rest_fixer/fix_silhouette/base_height_adjustment", PROPERTY_HINT_RANGE, "-1,1,0.01"), 0.0));
52 }
53}
54
55void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory p_category, Node *p_base_scene, Node *p_node, Ref<Resource> p_resource, const Dictionary &p_options) {
56 if (p_category == INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE) {
57 // Prepare objects.
58 Object *map = p_options["retarget/bone_map"].get_validated_object();
59 if (!map) {
60 return;
61 }
62 BoneMap *bone_map = Object::cast_to<BoneMap>(map);
63 Ref<SkeletonProfile> profile = bone_map->get_profile();
64 if (!profile.is_valid()) {
65 return;
66 }
67 Skeleton3D *src_skeleton = Object::cast_to<Skeleton3D>(p_node);
68 if (!src_skeleton) {
69 return;
70 }
71
72 bool is_renamed = bool(p_options["retarget/bone_renamer/rename_bones"]);
73 Array filter = p_options["retarget/rest_fixer/fix_silhouette/filter"];
74 bool is_rest_changed = false;
75
76 // Build profile skeleton.
77 Skeleton3D *prof_skeleton = memnew(Skeleton3D);
78 {
79 int prof_bone_len = profile->get_bone_size();
80 // Add single bones.
81 for (int i = 0; i < prof_bone_len; i++) {
82 prof_skeleton->add_bone(profile->get_bone_name(i));
83 prof_skeleton->set_bone_rest(i, profile->get_reference_pose(i));
84 }
85 // Set parents.
86 for (int i = 0; i < prof_bone_len; i++) {
87 int parent = profile->find_bone(profile->get_bone_parent(i));
88 if (parent >= 0) {
89 prof_skeleton->set_bone_parent(i, parent);
90 }
91 }
92 }
93
94 // Get global transform.
95 Transform3D global_transform;
96 if (bool(p_options["retarget/rest_fixer/apply_node_transforms"])) {
97 Node *pr = src_skeleton;
98 while (pr) {
99 Node3D *pr3d = Object::cast_to<Node3D>(pr);
100 if (pr3d) {
101 global_transform = pr3d->get_transform() * global_transform;
102 pr3d->set_transform(Transform3D());
103 }
104 pr = pr->get_parent();
105 }
106 global_transform.origin = Vector3(); // Translation by a Node is not a bone animation, so the retargeted model should be at the origin.
107 }
108
109 // Apply node transforms.
110 if (bool(p_options["retarget/rest_fixer/apply_node_transforms"])) {
111 Vector3 scl = global_transform.basis.get_scale_local();
112
113 Vector<int> bones_to_process = src_skeleton->get_parentless_bones();
114 for (int i = 0; i < bones_to_process.size(); i++) {
115 src_skeleton->set_bone_rest(bones_to_process[i], global_transform.orthonormalized() * src_skeleton->get_bone_rest(bones_to_process[i]));
116 }
117
118 while (bones_to_process.size() > 0) {
119 int src_idx = bones_to_process[0];
120 bones_to_process.erase(src_idx);
121 Vector<int> src_children = src_skeleton->get_bone_children(src_idx);
122 for (int i = 0; i < src_children.size(); i++) {
123 bones_to_process.push_back(src_children[i]);
124 }
125 src_skeleton->set_bone_rest(src_idx, Transform3D(src_skeleton->get_bone_rest(src_idx).basis, src_skeleton->get_bone_rest(src_idx).origin * scl));
126 }
127
128 // Fix animation.
129 bones_to_process = src_skeleton->get_parentless_bones();
130 {
131 TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
132 while (nodes.size()) {
133 AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
134 List<StringName> anims;
135 ap->get_animation_list(&anims);
136 for (const StringName &name : anims) {
137 Ref<Animation> anim = ap->get_animation(name);
138 int track_len = anim->get_track_count();
139 for (int i = 0; i < track_len; i++) {
140 if (anim->track_get_path(i).get_subname_count() != 1 || !(anim->track_get_type(i) == Animation::TYPE_POSITION_3D || anim->track_get_type(i) == Animation::TYPE_ROTATION_3D || anim->track_get_type(i) == Animation::TYPE_SCALE_3D)) {
141 continue;
142 }
143
144 if (anim->track_is_compressed(i)) {
145 continue; // Shouldn't occur in internal_process().
146 }
147
148 String track_path = String(anim->track_get_path(i).get_concatenated_names());
149 Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path));
150 ERR_CONTINUE(!node);
151
152 Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
153 if (!track_skeleton || track_skeleton != src_skeleton) {
154 continue;
155 }
156
157 StringName bn = anim->track_get_path(i).get_subname(0);
158 if (!bn) {
159 continue;
160 }
161
162 int bone_idx = src_skeleton->find_bone(bn);
163 int key_len = anim->track_get_key_count(i);
164 if (anim->track_get_type(i) == Animation::TYPE_POSITION_3D) {
165 if (bones_to_process.has(bone_idx)) {
166 for (int j = 0; j < key_len; j++) {
167 Vector3 ps = static_cast<Vector3>(anim->track_get_key_value(i, j));
168 anim->track_set_key_value(i, j, global_transform.basis.xform(ps) + global_transform.origin);
169 }
170 } else {
171 for (int j = 0; j < key_len; j++) {
172 Vector3 ps = static_cast<Vector3>(anim->track_get_key_value(i, j));
173 anim->track_set_key_value(i, j, ps * scl);
174 }
175 }
176 } else if (bones_to_process.has(bone_idx)) {
177 if (anim->track_get_type(i) == Animation::TYPE_ROTATION_3D) {
178 for (int j = 0; j < key_len; j++) {
179 Quaternion qt = static_cast<Quaternion>(anim->track_get_key_value(i, j));
180 anim->track_set_key_value(i, j, global_transform.basis.get_rotation_quaternion() * qt);
181 }
182 } else {
183 for (int j = 0; j < key_len; j++) {
184 Basis sc = Basis().scaled(static_cast<Vector3>(anim->track_get_key_value(i, j)));
185 anim->track_set_key_value(i, j, (global_transform.basis * sc).get_scale());
186 }
187 }
188 }
189 }
190 }
191 }
192 }
193
194 is_rest_changed = true;
195 }
196
197 // Complement Rotation track for compatibility between different rests.
198 {
199 TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
200 while (nodes.size()) {
201 AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
202 List<StringName> anims;
203 ap->get_animation_list(&anims);
204 for (const StringName &name : anims) {
205 Ref<Animation> anim = ap->get_animation(name);
206 int track_len = anim->get_track_count();
207
208 // Detect does the animation have skeleton's TRS track.
209 String track_path;
210 bool found_skeleton = false;
211 for (int i = 0; i < track_len; i++) {
212 if (anim->track_get_path(i).get_subname_count() != 1 || !(anim->track_get_type(i) == Animation::TYPE_POSITION_3D || anim->track_get_type(i) == Animation::TYPE_ROTATION_3D || anim->track_get_type(i) == Animation::TYPE_SCALE_3D)) {
213 continue;
214 }
215 track_path = String(anim->track_get_path(i).get_concatenated_names());
216 Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path));
217 if (node) {
218 Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
219 if (track_skeleton && track_skeleton == src_skeleton) {
220 found_skeleton = true;
221 break;
222 }
223 }
224 }
225
226 if (!found_skeleton) {
227 continue;
228 }
229
230 // Search and insert rot track if it doesn't exist.
231 for (int prof_idx = 0; prof_idx < prof_skeleton->get_bone_count(); prof_idx++) {
232 String bone_name = is_renamed ? prof_skeleton->get_bone_name(prof_idx) : String(bone_map->get_skeleton_bone_name(prof_skeleton->get_bone_name(prof_idx)));
233 if (bone_name.is_empty()) {
234 continue;
235 }
236 int src_idx = src_skeleton->find_bone(bone_name);
237 if (src_idx == -1) {
238 continue;
239 }
240 String insert_path = track_path + ":" + bone_name;
241 int rot_track = anim->find_track(insert_path, Animation::TYPE_ROTATION_3D);
242 if (rot_track == -1) {
243 int track = anim->add_track(Animation::TYPE_ROTATION_3D);
244 anim->track_set_path(track, insert_path);
245 anim->rotation_track_insert_key(track, 0, src_skeleton->get_bone_rest(src_idx).basis.get_rotation_quaternion());
246 }
247 }
248 }
249 }
250 }
251
252 // Fix silhouette.
253 Vector<Transform3D> silhouette_diff; // Transform values to be ignored when overwrite axis.
254 silhouette_diff.resize(src_skeleton->get_bone_count());
255 Transform3D *silhouette_diff_w = silhouette_diff.ptrw();
256 LocalVector<Transform3D> pre_silhouette_skeleton_global_rest;
257 for (int i = 0; i < src_skeleton->get_bone_count(); i++) {
258 pre_silhouette_skeleton_global_rest.push_back(src_skeleton->get_bone_global_rest(i));
259 }
260 if (bool(p_options["retarget/rest_fixer/fix_silhouette/enable"])) {
261 Vector<int> bones_to_process = prof_skeleton->get_parentless_bones();
262 while (bones_to_process.size() > 0) {
263 int prof_idx = bones_to_process[0];
264 bones_to_process.erase(prof_idx);
265 Vector<int> prof_children = prof_skeleton->get_bone_children(prof_idx);
266 for (int i = 0; i < prof_children.size(); i++) {
267 bones_to_process.push_back(prof_children[i]);
268 }
269
270 // Calc virtual/looking direction with origins.
271 bool is_filtered = false;
272 for (int i = 0; i < filter.size(); i++) {
273 if (String(filter[i]) == prof_skeleton->get_bone_name(prof_idx)) {
274 is_filtered = true;
275 break;
276 }
277 }
278 if (is_filtered) {
279 continue;
280 }
281
282 int src_idx = src_skeleton->find_bone(is_renamed ? prof_skeleton->get_bone_name(prof_idx) : String(bone_map->get_skeleton_bone_name(prof_skeleton->get_bone_name(prof_idx))));
283 if (src_idx < 0 || profile->get_tail_direction(prof_idx) == SkeletonProfile::TAIL_DIRECTION_END) {
284 continue;
285 }
286 Vector3 prof_tail;
287 Vector3 src_tail;
288 if (profile->get_tail_direction(prof_idx) == SkeletonProfile::TAIL_DIRECTION_AVERAGE_CHILDREN) {
289 PackedInt32Array prof_bone_children = prof_skeleton->get_bone_children(prof_idx);
290 int children_size = prof_bone_children.size();
291 if (children_size == 0) {
292 continue;
293 }
294 bool exist_all_children = true;
295 for (int i = 0; i < children_size; i++) {
296 int prof_child_idx = prof_bone_children[i];
297 int src_child_idx = src_skeleton->find_bone(is_renamed ? prof_skeleton->get_bone_name(prof_child_idx) : String(bone_map->get_skeleton_bone_name(prof_skeleton->get_bone_name(prof_child_idx))));
298 if (src_child_idx < 0) {
299 exist_all_children = false;
300 break;
301 }
302 prof_tail = prof_tail + prof_skeleton->get_bone_global_rest(prof_child_idx).origin;
303 src_tail = src_tail + src_skeleton->get_bone_global_rest(src_child_idx).origin;
304 }
305 if (!exist_all_children) {
306 continue;
307 }
308 prof_tail = prof_tail / children_size;
309 src_tail = src_tail / children_size;
310 }
311 if (profile->get_tail_direction(prof_idx) == SkeletonProfile::TAIL_DIRECTION_SPECIFIC_CHILD) {
312 int prof_tail_idx = prof_skeleton->find_bone(profile->get_bone_tail(prof_idx));
313 if (prof_tail_idx < 0) {
314 continue;
315 }
316 int src_tail_idx = src_skeleton->find_bone(is_renamed ? prof_skeleton->get_bone_name(prof_tail_idx) : String(bone_map->get_skeleton_bone_name(prof_skeleton->get_bone_name(prof_tail_idx))));
317 if (src_tail_idx < 0) {
318 continue;
319 }
320 prof_tail = prof_skeleton->get_bone_global_rest(prof_tail_idx).origin;
321 src_tail = src_skeleton->get_bone_global_rest(src_tail_idx).origin;
322 }
323
324 Vector3 prof_head = prof_skeleton->get_bone_global_rest(prof_idx).origin;
325 Vector3 src_head = src_skeleton->get_bone_global_rest(src_idx).origin;
326
327 Vector3 prof_dir = prof_tail - prof_head;
328 Vector3 src_dir = src_tail - src_head;
329
330 // Rotate rest.
331 if (Math::abs(Math::rad_to_deg(src_dir.angle_to(prof_dir))) > float(p_options["retarget/rest_fixer/fix_silhouette/threshold"])) {
332 // Get rotation difference.
333 Vector3 up_vec; // Need to rotate other than roll axis.
334 switch (Vector3(abs(src_dir.x), abs(src_dir.y), abs(src_dir.z)).min_axis_index()) {
335 case Vector3::AXIS_X: {
336 up_vec = Vector3(1, 0, 0);
337 } break;
338 case Vector3::AXIS_Y: {
339 up_vec = Vector3(0, 1, 0);
340 } break;
341 case Vector3::AXIS_Z: {
342 up_vec = Vector3(0, 0, 1);
343 } break;
344 }
345 Basis src_b;
346 src_b = src_b.looking_at(src_dir, up_vec);
347 Basis prof_b;
348 prof_b = src_b.looking_at(prof_dir, up_vec);
349 if (prof_b.is_equal_approx(Basis())) {
350 continue; // May not need to rotate.
351 }
352 Basis diff_b = prof_b * src_b.inverse();
353
354 // Apply rotation difference as global transform to skeleton.
355 Basis src_pg;
356 int src_parent = src_skeleton->get_bone_parent(src_idx);
357 if (src_parent >= 0) {
358 src_pg = src_skeleton->get_bone_global_rest(src_parent).basis;
359 }
360 Transform3D fixed_rest = Transform3D(src_pg.inverse() * diff_b * src_pg * src_skeleton->get_bone_rest(src_idx).basis, src_skeleton->get_bone_rest(src_idx).origin);
361 src_skeleton->set_bone_rest(src_idx, fixed_rest);
362 }
363 }
364
365 // Adjust scale base bone height.
366 float base_adjustment = float(p_options["retarget/rest_fixer/fix_silhouette/base_height_adjustment"]);
367 if (!Math::is_zero_approx(base_adjustment)) {
368 StringName scale_base_bone_name = profile->get_scale_base_bone();
369 int src_bone_idx = src_skeleton->find_bone(scale_base_bone_name);
370 Transform3D src_rest = src_skeleton->get_bone_rest(src_bone_idx);
371 src_skeleton->set_bone_rest(src_bone_idx, Transform3D(src_rest.basis, Vector3(src_rest.origin.x, src_rest.origin.y + base_adjustment, src_rest.origin.z)));
372
373 TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
374 while (nodes.size()) {
375 AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
376 List<StringName> anims;
377 ap->get_animation_list(&anims);
378 for (const StringName &name : anims) {
379 Ref<Animation> anim = ap->get_animation(name);
380 int track_len = anim->get_track_count();
381 for (int i = 0; i < track_len; i++) {
382 if (anim->track_get_path(i).get_subname_count() != 1 || anim->track_get_type(i) != Animation::TYPE_POSITION_3D) {
383 continue;
384 }
385
386 if (anim->track_is_compressed(i)) {
387 continue; // Shouldn't occur in internal_process().
388 }
389
390 String track_path = String(anim->track_get_path(i).get_concatenated_names());
391 Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path));
392 ERR_CONTINUE(!node);
393
394 Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
395 if (!track_skeleton || track_skeleton != src_skeleton) {
396 continue;
397 }
398
399 StringName bn = anim->track_get_path(i).get_concatenated_subnames();
400 if (bn != scale_base_bone_name) {
401 continue;
402 }
403
404 int key_len = anim->track_get_key_count(i);
405 for (int j = 0; j < key_len; j++) {
406 Vector3 pos = static_cast<Vector3>(anim->track_get_key_value(i, j));
407 pos.y += base_adjustment;
408 anim->track_set_key_value(i, j, pos);
409 }
410 }
411 }
412 }
413 }
414
415 // For skin modification in overwrite rest.
416 for (int i = 0; i < src_skeleton->get_bone_count(); i++) {
417 silhouette_diff_w[i] = pre_silhouette_skeleton_global_rest[i] * src_skeleton->get_bone_global_rest(i).affine_inverse();
418 }
419
420 is_rest_changed = true;
421 }
422
423 // Set motion scale to Skeleton if normalize position tracks.
424 if (bool(p_options["retarget/rest_fixer/normalize_position_tracks"])) {
425 int src_bone_idx = src_skeleton->find_bone(profile->get_scale_base_bone());
426 if (src_bone_idx >= 0) {
427 real_t motion_scale = abs(src_skeleton->get_bone_global_rest(src_bone_idx).origin.y);
428 if (motion_scale > 0) {
429 src_skeleton->set_motion_scale(motion_scale);
430 }
431 }
432
433 TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
434 while (nodes.size()) {
435 AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
436 List<StringName> anims;
437 ap->get_animation_list(&anims);
438 for (const StringName &name : anims) {
439 Ref<Animation> anim = ap->get_animation(name);
440 int track_len = anim->get_track_count();
441 for (int i = 0; i < track_len; i++) {
442 if (anim->track_get_path(i).get_subname_count() != 1 || anim->track_get_type(i) != Animation::TYPE_POSITION_3D) {
443 continue;
444 }
445
446 if (anim->track_is_compressed(i)) {
447 continue; // Shouldn't occur in internal_process().
448 }
449
450 String track_path = String(anim->track_get_path(i).get_concatenated_names());
451 Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path));
452 ERR_CONTINUE(!node);
453
454 Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
455 if (!track_skeleton || track_skeleton != src_skeleton) {
456 continue;
457 }
458
459 real_t mlt = 1 / src_skeleton->get_motion_scale();
460 int key_len = anim->track_get_key_count(i);
461 for (int j = 0; j < key_len; j++) {
462 Vector3 pos = static_cast<Vector3>(anim->track_get_key_value(i, j));
463 anim->track_set_key_value(i, j, pos * mlt);
464 }
465 }
466 }
467 }
468 }
469
470 // Overwrite axis.
471 if (bool(p_options["retarget/rest_fixer/overwrite_axis"])) {
472 LocalVector<Transform3D> old_skeleton_rest;
473 LocalVector<Transform3D> old_skeleton_global_rest;
474 for (int i = 0; i < src_skeleton->get_bone_count(); i++) {
475 old_skeleton_rest.push_back(src_skeleton->get_bone_rest(i));
476 old_skeleton_global_rest.push_back(src_skeleton->get_bone_global_rest(i));
477 }
478
479 Vector<Basis> diffs;
480 diffs.resize(src_skeleton->get_bone_count());
481 Basis *diffs_w = diffs.ptrw();
482
483 Vector<int> bones_to_process = src_skeleton->get_parentless_bones();
484 while (bones_to_process.size() > 0) {
485 int src_idx = bones_to_process[0];
486 bones_to_process.erase(src_idx);
487 Vector<int> src_children = src_skeleton->get_bone_children(src_idx);
488 for (int i = 0; i < src_children.size(); i++) {
489 bones_to_process.push_back(src_children[i]);
490 }
491
492 Basis tgt_rot;
493 StringName src_bone_name = is_renamed ? StringName(src_skeleton->get_bone_name(src_idx)) : bone_map->find_profile_bone_name(src_skeleton->get_bone_name(src_idx));
494 if (src_bone_name != StringName()) {
495 Basis src_pg;
496 int src_parent_idx = src_skeleton->get_bone_parent(src_idx);
497 if (src_parent_idx >= 0) {
498 src_pg = src_skeleton->get_bone_global_rest(src_parent_idx).basis;
499 }
500
501 int prof_idx = profile->find_bone(src_bone_name);
502 if (prof_idx >= 0) {
503 tgt_rot = src_pg.inverse() * prof_skeleton->get_bone_global_rest(prof_idx).basis; // Mapped bone uses reference pose.
504 }
505 /*
506 // If there is rest-relative animation, this logic may be work fine, but currently not so...
507 } else {
508 // tgt_rot = src_pg.inverse() * old_skeleton_global_rest[src_idx].basis; // Non-Mapped bone keeps global rest.
509 }
510 */
511 }
512
513 if (src_skeleton->get_bone_parent(src_idx) >= 0) {
514 diffs_w[src_idx] = tgt_rot.inverse() * diffs[src_skeleton->get_bone_parent(src_idx)] * src_skeleton->get_bone_rest(src_idx).basis;
515 } else {
516 diffs_w[src_idx] = tgt_rot.inverse() * src_skeleton->get_bone_rest(src_idx).basis;
517 }
518
519 Basis diff;
520 if (src_skeleton->get_bone_parent(src_idx) >= 0) {
521 diff = diffs[src_skeleton->get_bone_parent(src_idx)];
522 }
523 src_skeleton->set_bone_rest(src_idx, Transform3D(tgt_rot, diff.xform(src_skeleton->get_bone_rest(src_idx).origin)));
524 }
525
526 // Fix animation.
527 {
528 TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
529 while (nodes.size()) {
530 AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
531 ERR_CONTINUE(!ap);
532 List<StringName> anims;
533 ap->get_animation_list(&anims);
534 for (const StringName &name : anims) {
535 Ref<Animation> anim = ap->get_animation(name);
536 int track_len = anim->get_track_count();
537 for (int i = 0; i < track_len; i++) {
538 if (anim->track_get_path(i).get_subname_count() != 1 || !(anim->track_get_type(i) == Animation::TYPE_POSITION_3D || anim->track_get_type(i) == Animation::TYPE_ROTATION_3D || anim->track_get_type(i) == Animation::TYPE_SCALE_3D)) {
539 continue;
540 }
541
542 if (anim->track_is_compressed(i)) {
543 continue; // Shouldn't occur in internal_process().
544 }
545
546 String track_path = String(anim->track_get_path(i).get_concatenated_names());
547 Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path));
548 ERR_CONTINUE(!node);
549
550 Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
551 if (!track_skeleton || track_skeleton != src_skeleton) {
552 continue;
553 }
554
555 StringName bn = anim->track_get_path(i).get_subname(0);
556 if (!bn) {
557 continue;
558 }
559
560 int bone_idx = src_skeleton->find_bone(bn);
561
562 Transform3D old_rest = old_skeleton_rest[bone_idx];
563 Transform3D new_rest = src_skeleton->get_bone_rest(bone_idx);
564 Transform3D old_pg;
565 Transform3D new_pg;
566 int parent_idx = src_skeleton->get_bone_parent(bone_idx);
567 if (parent_idx >= 0) {
568 old_pg = old_skeleton_global_rest[parent_idx];
569 new_pg = src_skeleton->get_bone_global_rest(parent_idx);
570 }
571
572 int key_len = anim->track_get_key_count(i);
573 if (anim->track_get_type(i) == Animation::TYPE_ROTATION_3D) {
574 Quaternion old_rest_q = old_rest.basis.get_rotation_quaternion();
575 Quaternion new_rest_q = new_rest.basis.get_rotation_quaternion();
576 Quaternion old_pg_q = old_pg.basis.get_rotation_quaternion();
577 Quaternion new_pg_q = new_pg.basis.get_rotation_quaternion();
578 for (int j = 0; j < key_len; j++) {
579 Quaternion qt = static_cast<Quaternion>(anim->track_get_key_value(i, j));
580 anim->track_set_key_value(i, j, new_pg_q.inverse() * old_pg_q * qt * old_rest_q.inverse() * old_pg_q.inverse() * new_pg_q * new_rest_q);
581 }
582 } else if (anim->track_get_type(i) == Animation::TYPE_SCALE_3D) {
583 Basis old_rest_b = old_rest.basis;
584 Basis new_rest_b = new_rest.basis;
585 Basis old_pg_b = old_pg.basis;
586 Basis new_pg_b = new_pg.basis;
587 for (int j = 0; j < key_len; j++) {
588 Basis sc = Basis().scaled(static_cast<Vector3>(anim->track_get_key_value(i, j)));
589 anim->track_set_key_value(i, j, (new_pg_b.inverse() * old_pg_b * sc * old_rest_b.inverse() * old_pg_b.inverse() * new_pg_b * new_rest_b).get_scale());
590 }
591 } else {
592 Vector3 old_rest_o = old_rest.origin;
593 Vector3 new_rest_o = new_rest.origin;
594 Quaternion old_pg_q = old_pg.basis.get_rotation_quaternion();
595 Quaternion new_pg_q = new_pg.basis.get_rotation_quaternion();
596 for (int j = 0; j < key_len; j++) {
597 Vector3 ps = static_cast<Vector3>(anim->track_get_key_value(i, j));
598 anim->track_set_key_value(i, j, new_pg_q.xform_inv(old_pg_q.xform(ps - old_rest_o)) + new_rest_o);
599 }
600 }
601 }
602 }
603 }
604 }
605
606 is_rest_changed = true;
607 }
608
609 if (is_rest_changed) {
610 // Fix skin.
611 {
612 HashSet<Ref<Skin>> mutated_skins;
613 TypedArray<Node> nodes = p_base_scene->find_children("*", "ImporterMeshInstance3D");
614 while (nodes.size()) {
615 ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(nodes.pop_back());
616 ERR_CONTINUE(!mi);
617
618 Ref<Skin> skin = mi->get_skin();
619 if (skin.is_null()) {
620 continue;
621 }
622 if (mutated_skins.has(skin)) {
623 continue;
624 }
625 mutated_skins.insert(skin);
626
627 Node *node = mi->get_node(mi->get_skeleton_path());
628 ERR_CONTINUE(!node);
629
630 Skeleton3D *mesh_skeleton = Object::cast_to<Skeleton3D>(node);
631 if (!mesh_skeleton || mesh_skeleton != src_skeleton) {
632 continue;
633 }
634
635 int skin_len = skin->get_bind_count();
636 for (int i = 0; i < skin_len; i++) {
637 StringName bn = skin->get_bind_name(i);
638 int bone_idx = src_skeleton->find_bone(bn);
639 if (bone_idx >= 0) {
640 Transform3D adjust_transform = src_skeleton->get_bone_global_rest(bone_idx).affine_inverse() * silhouette_diff[bone_idx].affine_inverse() * pre_silhouette_skeleton_global_rest[bone_idx];
641 adjust_transform.scale(global_transform.basis.get_scale_local());
642 skin->set_bind_pose(i, adjust_transform * skin->get_bind_pose(i));
643 }
644 }
645 }
646 nodes = src_skeleton->get_children();
647 while (nodes.size()) {
648 BoneAttachment3D *attachment = Object::cast_to<BoneAttachment3D>(nodes.pop_back());
649 if (attachment == nullptr) {
650 continue;
651 }
652 int bone_idx = attachment->get_bone_idx();
653 if (bone_idx == -1) {
654 bone_idx = src_skeleton->find_bone(attachment->get_bone_name());
655 }
656 ERR_CONTINUE(bone_idx < 0 || bone_idx >= src_skeleton->get_bone_count());
657 Transform3D adjust_transform = src_skeleton->get_bone_global_rest(bone_idx).affine_inverse() * silhouette_diff[bone_idx].affine_inverse() * pre_silhouette_skeleton_global_rest[bone_idx];
658 adjust_transform.scale(global_transform.basis.get_scale_local());
659
660 TypedArray<Node> child_nodes = attachment->get_children();
661 while (child_nodes.size()) {
662 Node3D *child = Object::cast_to<Node3D>(child_nodes.pop_back());
663 if (child == nullptr) {
664 continue;
665 }
666 child->set_transform(adjust_transform * child->get_transform());
667 }
668 }
669 }
670
671 // Init skeleton pose to new rest.
672 for (int i = 0; i < src_skeleton->get_bone_count(); i++) {
673 Transform3D fixed_rest = src_skeleton->get_bone_rest(i);
674 src_skeleton->set_bone_pose_position(i, fixed_rest.origin);
675 src_skeleton->set_bone_pose_rotation(i, fixed_rest.basis.get_rotation_quaternion());
676 src_skeleton->set_bone_pose_scale(i, fixed_rest.basis.get_scale());
677 }
678 }
679
680 memdelete(prof_skeleton);
681 }
682}
683
684PostImportPluginSkeletonRestFixer::PostImportPluginSkeletonRestFixer() {
685}
686