forked from sascha/godot
Remove animation 3D transform track, replace by loc/rot/scale tracks.
* `Animation.TYPE_TRANSFORM3D` track is gone. * Added POSITION_3D, ROTATION_3D, SCALE_3D tracks. * GLTF2, Collada, FBX importers will only import the track types found. * Skeleton3D bone poses are now Pos/Rot/Scale, pose matrix removed. * AnimationPlayer and AnimationTree animate these tracks separately, only when found. * Removed BakeReset code, is useless with these changes. This is the first in a series of commits designed to make the animation system in Godot more useful, which includes: * Better compatibility with Autodesk products * Better reusability of animations across models (including retargeting). * Proper animation compression. * etc. *Note* GLTF2 animation saving went broken with this PR, needs to be fixed in a subsequent one.4.0
parent
f9aec342dc
commit
ec19ed3723
@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
height="10"
|
||||
viewBox="0 0 10 10"
|
||||
width="10"
|
||||
version="1.1"
|
||||
id="svg12"
|
||||
sodipodi:docname="KeyTrackPosition.svg"
|
||||
inkscape:version="1.1 (1:1.1+202106031931+af4d65493e)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs16" />
|
||||
<sodipodi:namedview
|
||||
id="namedview14"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="42.2"
|
||||
inkscape:cx="12.78436"
|
||||
inkscape:cy="6.1729858"
|
||||
inkscape:window-width="1848"
|
||||
inkscape:window-height="1016"
|
||||
inkscape:window-x="72"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg12" />
|
||||
<ellipse
|
||||
style="fill:none;fill-opacity:0.401212;stroke:none;stroke-width:4.7811;stroke-linejoin:round"
|
||||
id="path921"
|
||||
cx="-0.88986981"
|
||||
cy="6.0959954"
|
||||
rx="1.2495773"
|
||||
ry="1.0867468" />
|
||||
<path
|
||||
d="M 4.949661,0.60426977 A 0.6444116,0.6444116 0 0 0 4.504153,0.79178767 L 3.215459,2.0804819 4.12663,2.9916532 4.95977,2.1585124 5.792911,2.9916532 6.704083,2.0804819 5.415388,0.79178767 A 0.6444116,0.6444116 0 0 0 4.949744,0.60426977 Z M 1.926771,3.3691634 0.638077,4.6578577 a 0.6444116,0.6444116 0 0 0 0,0.9111713 L 1.926771,6.8577233 2.837942,5.946552 2.004801,5.1134111 2.837942,4.2802702 1.926771,3.3690989 Z m 6.065948,0 -0.911171,0.9111713 0.83314,0.8331409 -0.83314,0.8331408 0.911171,0.9111714 1.288694,-1.2886944 a 0.6444116,0.6444116 0 0 0 0,-0.9111713 L 7.992719,3.3692278 Z M 4.959777,3.8247361 A 1.2886943,1.2886943 0 0 0 3.671083,5.1134305 1.2886943,1.2886943 0 0 0 4.959777,6.4021248 1.2886943,1.2886943 0 0 0 6.248471,5.1134305 1.2886943,1.2886943 0 0 0 4.959777,3.8247361 Z m -0.83314,3.4105296 -0.911172,0.9111715 1.288694,1.288694 a 0.6444116,0.6444116 0 0 0 0.911171,0 L 6.704025,8.1464372 5.792853,7.2352657 4.959712,8.0684062 4.126572,7.2352657 Z"
|
||||
fill="#e0e0e0"
|
||||
fill-opacity="0.99608"
|
||||
id="path1400"
|
||||
style="fill:#ea7940;fill-opacity:1;stroke-width:0.644347" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
height="10"
|
||||
viewBox="0 0 10 10"
|
||||
width="10"
|
||||
version="1.1"
|
||||
id="svg12"
|
||||
sodipodi:docname="KeyTrackRotation.svg"
|
||||
inkscape:version="1.1 (1:1.1+202106031931+af4d65493e)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs16" />
|
||||
<sodipodi:namedview
|
||||
id="namedview14"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="42.2"
|
||||
inkscape:cx="1.9075829"
|
||||
inkscape:cy="5.8175355"
|
||||
inkscape:window-width="1848"
|
||||
inkscape:window-height="1016"
|
||||
inkscape:window-x="72"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg12" />
|
||||
<ellipse
|
||||
style="fill:none;fill-opacity:0.401212;stroke:none;stroke-width:4.7811;stroke-linejoin:round"
|
||||
id="path921"
|
||||
cx="-0.88986981"
|
||||
cy="6.0959954"
|
||||
rx="1.2495773"
|
||||
ry="1.0867468" />
|
||||
<path
|
||||
d="m 5.0711986,0.88214062 a 4.1086779,4.1086779 0 0 0 -0.178839,0.00115 4.1086779,4.1086779 0 0 0 -0.409265,0.033245 A 4.1086779,4.1086779 0 0 0 0.99001362,4.1883346 4.1086779,4.1086779 0 0 0 2.1467236,7.9244144 h -0.648877 v 1.1739077 h 2.347816 a 0.58701268,0.58701268 0 0 0 0.569756,-0.729119 l -0.586953,-2.3478164 -1.139514,0.2854534 0.165082,0.6580347 a 2.9347699,2.9347699 0 0 1 -0.769204,-1.9752178 2.9347699,2.9347699 0 0 1 2.93477,-2.93477 2.9347699,2.9347699 0 0 1 2.93477,2.93477 2.9347699,2.9347699 0 0 1 -0.860944,2.0738257 l 0.831127,0.8311266 A 4.1086779,4.1086779 0 0 0 8.7040866,3.1726236 4.1086779,4.1086779 0 0 0 5.0711336,0.88215292 Z m -0.05159,2.93359608 a 1.173908,1.173908 0 0 0 -1.173907,1.173908 1.173908,1.173908 0 0 0 1.173907,1.173908 1.173908,1.173908 0 0 0 1.173909,-1.173908 1.173908,1.173908 0 0 0 -1.173909,-1.173908 z"
|
||||
fill="#e0e0e0"
|
||||
fill-opacity="0.99608"
|
||||
id="path1165"
|
||||
style="fill:#ff2b88;fill-opacity:1;stroke-width:0.586954" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
height="10"
|
||||
viewBox="0 0 10 10"
|
||||
width="10"
|
||||
version="1.1"
|
||||
id="svg12"
|
||||
sodipodi:docname="KeyTrackScale.svg"
|
||||
inkscape:version="1.1 (1:1.1+202106031931+af4d65493e)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs16" />
|
||||
<sodipodi:namedview
|
||||
id="namedview14"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="42.2"
|
||||
inkscape:cx="1.9075829"
|
||||
inkscape:cy="5.8175355"
|
||||
inkscape:window-width="1848"
|
||||
inkscape:window-height="1016"
|
||||
inkscape:window-x="72"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg12" />
|
||||
<ellipse
|
||||
style="fill:none;fill-opacity:0.401212;stroke:none;stroke-width:4.7811;stroke-linejoin:round"
|
||||
id="path921"
|
||||
cx="-0.88986981"
|
||||
cy="6.0959954"
|
||||
rx="1.2495773"
|
||||
ry="1.0867468" />
|
||||
<path
|
||||
d="M 5.5742494,0.94786723 A 0.58774585,0.58774585 0 0 0 4.9865036,1.535613 0.58774585,0.58774585 0 0 0 5.5742494,2.1233589 h 1.519852 L 6.334146,2.8833142 7.1652774,3.7144456 7.9252328,2.9544903 V 4.4743422 A 0.58774585,0.58774585 0 0 0 8.5129787,5.0620881 0.58774585,0.58774585 0 0 0 9.1007245,4.4743422 V 1.535613 A 0.58780462,0.58780462 0 0 0 8.5129787,0.94786723 Z M 4.9865036,3.8865964 A 1.1754917,1.1754917 0 0 0 3.8110119,5.0620881 1.1754917,1.1754917 0 0 0 4.9865036,6.2375798 1.1754917,1.1754917 0 0 0 6.1619953,5.0620881 1.1754917,1.1754917 0 0 0 4.9865036,3.8865964 Z M 1.4600285,5.0620881 A 0.58774585,0.58774585 0 0 0 0.8722826,5.6498339 V 8.5885638 A 0.58780462,0.58780462 0 0 0 1.4600285,9.1763092 H 4.3987577 A 0.58774585,0.58774585 0 0 0 4.9865036,8.5885638 0.58774585,0.58774585 0 0 0 4.3987577,8.0008173 H 2.8789057 L 3.6388611,7.2408619 2.8077297,6.4097305 2.0477743,7.1696859 V 5.6498339 A 0.58774585,0.58774585 0 0 0 1.4600285,5.0620881 Z"
|
||||
fill="#e0e0e0"
|
||||
fill-opacity="0.99608"
|
||||
id="path7"
|
||||
style="fill:#eac840;fill-opacity:1;stroke-width:0.587745" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
height="10"
|
||||
viewBox="0 0 10 10"
|
||||
width="10"
|
||||
version="1.1"
|
||||
id="svg1678"
|
||||
sodipodi:docname="KeyXPosition.svg"
|
||||
inkscape:version="1.1 (1:1.1+202106031931+af4d65493e)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1682" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1680"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="84.4"
|
||||
inkscape:cx="4.9940758"
|
||||
inkscape:cy="5.0059242"
|
||||
inkscape:window-width="1848"
|
||||
inkscape:window-height="1016"
|
||||
inkscape:window-x="72"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1678" />
|
||||
<rect
|
||||
fill="#ea7940"
|
||||
height="6.1027"
|
||||
ry=".76286"
|
||||
transform="matrix(.70710678 -.70710678 .70710678 .70710678 0 -1042.4)"
|
||||
width="6.1027"
|
||||
x="-740.13947"
|
||||
y="741.10779"
|
||||
id="rect1676" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
height="10"
|
||||
viewBox="0 0 10 10"
|
||||
width="10"
|
||||
version="1.1"
|
||||
id="svg1678"
|
||||
sodipodi:docname="KeyXRotation.svg"
|
||||
inkscape:version="1.1 (1:1.1+202106031931+af4d65493e)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1682" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1680"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="84.4"
|
||||
inkscape:cx="0.32582938"
|
||||
inkscape:cy="5.0059242"
|
||||
inkscape:window-width="1848"
|
||||
inkscape:window-height="1016"
|
||||
inkscape:window-x="72"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1678" />
|
||||
<rect
|
||||
fill="#ea7940"
|
||||
height="6.1027002"
|
||||
ry="0.76286"
|
||||
transform="rotate(-45,-1258.2881,-521.2)"
|
||||
width="6.1030002"
|
||||
x="-740.13947"
|
||||
y="741.10779"
|
||||
id="rect1676"
|
||||
style="fill:#ee3c94;fill-opacity:1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
height="10"
|
||||
viewBox="0 0 10 10"
|
||||
width="10"
|
||||
version="1.1"
|
||||
id="svg1678"
|
||||
sodipodi:docname="KeyXScale.svg"
|
||||
inkscape:version="1.1 (1:1.1+202106031931+af4d65493e)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1682" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1680"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="84.4"
|
||||
inkscape:cx="2.6658768"
|
||||
inkscape:cy="5.0059242"
|
||||
inkscape:window-width="1473"
|
||||
inkscape:window-height="752"
|
||||
inkscape:window-x="122"
|
||||
inkscape:window-y="114"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg1678" />
|
||||
<rect
|
||||
fill="#ea7940"
|
||||
height="6.1027002"
|
||||
ry="0.76286"
|
||||
transform="rotate(-45,-1258.2881,-521.2)"
|
||||
width="6.1030002"
|
||||
x="-740.13947"
|
||||
y="741.10779"
|
||||
id="rect1676"
|
||||
style="fill:#dbbf4f;fill-opacity:1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@ -1,234 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* editor_importer_bake_reset.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "editor/import/editor_importer_bake_reset.h"
|
||||
|
||||
#include "core/error/error_list.h"
|
||||
#include "core/error/error_macros.h"
|
||||
#include "core/math/transform_3d.h"
|
||||
#include "resource_importer_scene.h"
|
||||
#include "scene/3d/importer_mesh_instance_3d.h"
|
||||
#include "scene/3d/mesh_instance_3d.h"
|
||||
#include "scene/3d/node_3d.h"
|
||||
#include "scene/3d/skeleton_3d.h"
|
||||
#include "scene/animation/animation_player.h"
|
||||
|
||||
// Given that an engineering team has made a reference character, one wants ten animators to create animations.
|
||||
// Currently, a tech artist needs to combine the ten files into one exported gltf2 to import into Godot Engine.
|
||||
// We bake the RESET animation and then set it to identity,
|
||||
// so that rigs with corresponding RESET animation can have their animations transferred with ease.
|
||||
//
|
||||
// The original algorithm for the code was used to change skeleton bone rolls to be parent to child.
|
||||
//
|
||||
// Reference https://github.com/godotengine/godot-proposals/issues/2961
|
||||
void BakeReset::_bake_animation_pose(Node *scene, const String &p_bake_anim) {
|
||||
Map<StringName, BakeResetRestBone> r_rest_bones;
|
||||
Vector<Node3D *> r_meshes;
|
||||
List<Node *> queue;
|
||||
queue.push_back(scene);
|
||||
while (!queue.is_empty()) {
|
||||
List<Node *>::Element *E = queue.front();
|
||||
Node *node = E->get();
|
||||
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(node);
|
||||
// Step 1: import scene with animations into the rest bones data structure.
|
||||
_fetch_reset_animation(ap, r_rest_bones, p_bake_anim);
|
||||
|
||||
int child_count = node->get_child_count();
|
||||
for (int i = 0; i < child_count; i++) {
|
||||
queue.push_back(node->get_child(i));
|
||||
}
|
||||
queue.pop_front();
|
||||
}
|
||||
|
||||
queue.push_back(scene);
|
||||
while (!queue.is_empty()) {
|
||||
List<Node *>::Element *E = queue.front();
|
||||
Node *node = E->get();
|
||||
ImporterMeshInstance3D *editor_mesh_3d = scene->cast_to<ImporterMeshInstance3D>(node);
|
||||
MeshInstance3D *mesh_3d = scene->cast_to<MeshInstance3D>(node);
|
||||
if (scene->cast_to<Skeleton3D>(node)) {
|
||||
Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node);
|
||||
|
||||
// Step 2: Bake the RESET animation from the RestBone to the skeleton.
|
||||
_fix_skeleton(skeleton, r_rest_bones);
|
||||
}
|
||||
if (editor_mesh_3d) {
|
||||
NodePath path = editor_mesh_3d->get_skeleton_path();
|
||||
if (!path.is_empty() && editor_mesh_3d->get_node_or_null(path) && Object::cast_to<Skeleton3D>(editor_mesh_3d->get_node_or_null(path))) {
|
||||
r_meshes.push_back(editor_mesh_3d);
|
||||
}
|
||||
} else if (mesh_3d) {
|
||||
NodePath path = mesh_3d->get_skeleton_path();
|
||||
if (!path.is_empty() && mesh_3d->get_node_or_null(path) && Object::cast_to<Skeleton3D>(mesh_3d->get_node_or_null(path))) {
|
||||
r_meshes.push_back(mesh_3d);
|
||||
}
|
||||
}
|
||||
int child_count = node->get_child_count();
|
||||
for (int i = 0; i < child_count; i++) {
|
||||
queue.push_back(node->get_child(i));
|
||||
}
|
||||
queue.pop_front();
|
||||
}
|
||||
|
||||
queue.push_back(scene);
|
||||
while (!queue.is_empty()) {
|
||||
List<Node *>::Element *E = queue.front();
|
||||
Node *node = E->get();
|
||||
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(node);
|
||||
if (ap) {
|
||||
// Step 3: Key all RESET animation frames to identity.
|
||||
_align_animations(ap, r_rest_bones);
|
||||
}
|
||||
|
||||
int child_count = node->get_child_count();
|
||||
for (int i = 0; i < child_count; i++) {
|
||||
queue.push_back(node->get_child(i));
|
||||
}
|
||||
queue.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
void BakeReset::_align_animations(AnimationPlayer *p_ap, const Map<StringName, BakeResetRestBone> &r_rest_bones) {
|
||||
ERR_FAIL_NULL(p_ap);
|
||||
List<StringName> anim_names;
|
||||
p_ap->get_animation_list(&anim_names);
|
||||
for (List<StringName>::Element *anim_i = anim_names.front(); anim_i; anim_i = anim_i->next()) {
|
||||
Ref<Animation> a = p_ap->get_animation(anim_i->get());
|
||||
ERR_CONTINUE(a.is_null());
|
||||
for (const KeyValue<StringName, BakeResetRestBone> &rest_bone_i : r_rest_bones) {
|
||||
int track = a->find_track(NodePath(rest_bone_i.key));
|
||||
if (track == -1) {
|
||||
continue;
|
||||
}
|
||||
int new_track = a->add_track(Animation::TYPE_TRANSFORM3D);
|
||||
NodePath new_path = NodePath(rest_bone_i.key);
|
||||
const BakeResetRestBone rest_bone = rest_bone_i.value;
|
||||
a->track_set_path(new_track, new_path);
|
||||
for (int key_i = 0; key_i < a->track_get_key_count(track); key_i++) {
|
||||
Vector3 loc;
|
||||
Quaternion rot;
|
||||
Vector3 scale;
|
||||
Error err = a->transform_track_get_key(track, key_i, &loc, &rot, &scale);
|
||||
ERR_CONTINUE(err);
|
||||
real_t time = a->track_get_key_time(track, key_i);
|
||||
rot.normalize();
|
||||
loc = loc - rest_bone.loc;
|
||||
rot = rest_bone.rest_delta.get_rotation_quaternion().inverse() * rot;
|
||||
rot.normalize();
|
||||
scale = Vector3(1, 1, 1) - (rest_bone.rest_delta.get_scale() - scale);
|
||||
// Apply the reverse of the rest changes to make the key be close to identity transform.
|
||||
a->transform_track_insert_key(new_track, time, loc, rot, scale);
|
||||
}
|
||||
a->remove_track(track);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BakeReset::_fetch_reset_animation(AnimationPlayer *p_ap, Map<StringName, BakeResetRestBone> &r_rest_bones, const String &p_bake_anim) {
|
||||
if (!p_ap) {
|
||||
return;
|
||||
}
|
||||
List<StringName> anim_names;
|
||||
p_ap->get_animation_list(&anim_names);
|
||||
Node *root = p_ap->get_owner();
|
||||
ERR_FAIL_NULL(root);
|
||||
if (!p_ap->has_animation(p_bake_anim)) {
|
||||
return;
|
||||
}
|
||||
Ref<Animation> a = p_ap->get_animation(p_bake_anim);
|
||||
if (a.is_null()) {
|
||||
return;
|
||||
}
|
||||
for (int32_t track = 0; track < a->get_track_count(); track++) {
|
||||
NodePath path = a->track_get_path(track);
|
||||
String string_path = path;
|
||||
Skeleton3D *skeleton = root->cast_to<Skeleton3D>(root->get_node(string_path.get_slice(":", 0)));
|
||||
if (!skeleton) {
|
||||
continue;
|
||||
}
|
||||
String bone_name = string_path.get_slice(":", 1);
|
||||
for (int key_i = 0; key_i < a->track_get_key_count(track); key_i++) {
|
||||
Vector3 loc;
|
||||
Quaternion rot;
|
||||
Vector3 scale;
|
||||
Error err = a->transform_track_get_key(track, key_i, &loc, &rot, &scale);
|
||||
if (err != OK) {
|
||||
ERR_PRINT_ONCE("Reset animation baker can't get key.");
|
||||
continue;
|
||||
}
|
||||
rot.normalize();
|
||||
Basis rot_basis = Basis(rot, scale);
|
||||
BakeResetRestBone rest_bone;
|
||||
rest_bone.rest_delta = rot_basis;
|
||||
rest_bone.loc = loc;
|
||||
// Store the animation into the RestBone.
|
||||
r_rest_bones[StringName(String(skeleton->get_owner()->get_path_to(skeleton)) + ":" + bone_name)] = rest_bone;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BakeReset::_fix_skeleton(Skeleton3D *p_skeleton, Map<StringName, BakeReset::BakeResetRestBone> &r_rest_bones) {
|
||||
int bone_count = p_skeleton->get_bone_count();
|
||||
|
||||
// First iterate through all the bones and update the RestBone.
|
||||
for (int j = 0; j < bone_count; j++) {
|
||||
StringName final_path = String(p_skeleton->get_owner()->get_path_to(p_skeleton)) + String(":") + p_skeleton->get_bone_name(j);
|
||||
BakeResetRestBone &rest_bone = r_rest_bones[final_path];
|
||||
rest_bone.rest_local = p_skeleton->get_bone_rest(j);
|
||||
}
|
||||
for (int i = 0; i < bone_count; i++) {
|
||||
int parent_bone = p_skeleton->get_bone_parent(i);
|
||||
String path = p_skeleton->get_owner()->get_path_to(p_skeleton);
|
||||
StringName final_path = String(path) + String(":") + p_skeleton->get_bone_name(parent_bone);
|
||||
if (parent_bone >= 0) {
|
||||
r_rest_bones[path].children.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
// When we apply transform to a bone, we also have to move all of its children in the opposite direction.
|
||||
for (int i = 0; i < bone_count; i++) {
|
||||
StringName final_path = String(p_skeleton->get_owner()->get_path_to(p_skeleton)) + String(":") + p_skeleton->get_bone_name(i);
|
||||
r_rest_bones[final_path].rest_local = r_rest_bones[final_path].rest_local * Transform3D(r_rest_bones[final_path].rest_delta, r_rest_bones[final_path].loc);
|
||||
// Iterate through the children and move in the opposite direction.
|
||||
for (int j = 0; j < r_rest_bones[final_path].children.size(); j++) {
|
||||
int child_index = r_rest_bones[final_path].children[j];
|
||||
StringName children_path = String(p_skeleton->get_name()) + String(":") + p_skeleton->get_bone_name(child_index);
|
||||
r_rest_bones[children_path].rest_local = Transform3D(r_rest_bones[final_path].rest_delta, r_rest_bones[final_path].loc).affine_inverse() * r_rest_bones[children_path].rest_local;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < bone_count; i++) {
|
||||
StringName final_path = String(p_skeleton->get_owner()->get_path_to(p_skeleton)) + String(":") + p_skeleton->get_bone_name(i);
|
||||
ERR_CONTINUE(!r_rest_bones.has(final_path));
|
||||
Transform3D rest_transform = r_rest_bones[final_path].rest_local;
|
||||
p_skeleton->set_bone_rest(i, rest_transform);
|
||||
}
|
||||
}
|
||||
@ -1,54 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* editor_importer_bake_reset.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef RESOURCE_IMPORTER_BAKE_RESET_H
|
||||
#define RESOURCE_IMPORTER_BAKE_RESET_H
|
||||
|
||||
#include "scene/main/node.h"
|
||||
|
||||
class Skeleton3D;
|
||||
class AnimationPlayer;
|
||||
class BakeReset {
|
||||
struct BakeResetRestBone {
|
||||
Transform3D rest_local;
|
||||
Basis rest_delta;
|
||||
Vector3 loc;
|
||||
Vector<int> children;
|
||||
};
|
||||
|
||||
public:
|
||||
void _bake_animation_pose(Node *scene, const String &p_bake_anim);
|
||||
|
||||
private:
|
||||
void _fix_skeleton(Skeleton3D *p_skeleton, Map<StringName, BakeReset::BakeResetRestBone> &r_rest_bones);
|
||||
void _align_animations(AnimationPlayer *p_ap, const Map<StringName, BakeResetRestBone> &r_rest_bones);
|
||||
void _fetch_reset_animation(AnimationPlayer *p_ap, Map<StringName, BakeResetRestBone> &r_rest_bones, const String &p_bake_anim);
|
||||
};
|
||||
#endif
|
||||
@ -1,314 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* animation_cache.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "animation_cache.h"
|
||||
|
||||
void AnimationCache::_node_exit_tree(Node *p_node) {
|
||||
//it is one shot, so it disconnects upon arrival
|
||||
|
||||
ERR_FAIL_COND(!connected_nodes.has(p_node));
|
||||
|
||||
connected_nodes.erase(p_node);
|
||||
|
||||
for (int i = 0; i < path_cache.size(); i++) {
|
||||
if (path_cache[i].node != p_node) {
|
||||
continue;
|
||||
}
|
||||
|
||||
path_cache.write[i].valid = false; //invalidate path cache
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationCache::_animation_changed() {
|
||||
_clear_cache();
|
||||
}
|
||||
|
||||
void AnimationCache::_clear_cache() {
|
||||
while (connected_nodes.size()) {
|
||||
connected_nodes.front()->get()->disconnect("tree_exiting", callable_mp(this, &AnimationCache::_node_exit_tree));
|
||||
connected_nodes.erase(connected_nodes.front());
|
||||
}
|
||||
path_cache.clear();
|
||||
cache_valid = false;
|
||||
cache_dirty = true;
|
||||
}
|
||||
|
||||
void AnimationCache::_update_cache() {
|
||||
cache_valid = false;
|
||||
|
||||
ERR_FAIL_COND(!root);
|
||||
ERR_FAIL_COND(!root->is_inside_tree());
|
||||
ERR_FAIL_COND(animation.is_null());
|
||||
|
||||
for (int i = 0; i < animation->get_track_count(); i++) {
|
||||
NodePath np = animation->track_get_path(i);
|
||||
|
||||
Node *node = root->get_node(np);
|
||||
if (!node) {
|
||||
path_cache.push_back(Path());
|
||||
ERR_CONTINUE_MSG(!node, "Invalid track path in animation '" + np + "'.");
|
||||
}
|
||||
|
||||
Path path;
|
||||
|
||||
Ref<Resource> res;
|
||||
|
||||
if (animation->track_get_type(i) == Animation::TYPE_TRANSFORM3D) {
|
||||
#ifndef _3D_DISABLED
|
||||
if (np.get_subname_count() > 1) {
|
||||
path_cache.push_back(Path());
|
||||
ERR_CONTINUE_MSG(animation->track_get_type(i) == Animation::TYPE_TRANSFORM3D, "Transform tracks can't have a subpath '" + np + "'.");
|
||||
}
|
||||
|
||||
Node3D *sp = Object::cast_to<Node3D>(node);
|
||||
|
||||
if (!sp) {
|
||||
path_cache.push_back(Path());
|
||||
ERR_CONTINUE_MSG(!sp, "Transform track not of type Node3D '" + np + "'.");
|
||||
}
|
||||
|
||||
if (np.get_subname_count() == 1) {
|
||||
StringName property = np.get_subname(0);
|
||||
String ps = property;
|
||||
|
||||
Skeleton3D *sk = Object::cast_to<Skeleton3D>(node);
|
||||
if (!sk) {
|
||||
path_cache.push_back(Path());
|
||||
ERR_CONTINUE_MSG(!sk, "Property defined in Transform track, but not a Skeleton! '" + np + "'.");
|
||||
}
|
||||
|
||||
int idx = sk->find_bone(ps);
|
||||
if (idx == -1) {
|
||||
path_cache.push_back(Path());
|
||||
ERR_CONTINUE_MSG(idx == -1, "Property defined in Transform track, but not a Skeleton Bone! '" + np + "'.");
|
||||
}
|
||||
|
||||
path.bone_idx = idx;
|
||||
path.skeleton = sk;
|
||||
}
|
||||
|
||||
path.node_3d = sp;
|
||||
#endif // _3D_DISABLED
|
||||
} else {
|
||||
if (np.get_subname_count() > 0) {
|
||||
RES res2;
|
||||
Vector<StringName> leftover_subpath;
|
||||
|
||||
// We don't want to cache the last resource unless it is a method call
|
||||
bool is_method = animation->track_get_type(i) == Animation::TYPE_METHOD;
|
||||
root->get_node_and_resource(np, res2, leftover_subpath, is_method);
|
||||
|
||||
if (res2.is_valid()) {
|
||||
path.resource = res2;
|
||||
} else {
|
||||
path.node = node;
|
||||
}
|
||||
path.object = res2.is_valid() ? res2.ptr() : (Object *)node;
|
||||
path.subpath = leftover_subpath;
|
||||
|
||||
} else {
|
||||
path.node = node;
|
||||
path.object = node;
|
||||
path.subpath = np.get_subnames();
|
||||
}
|
||||
}
|
||||
|
||||
if (animation->track_get_type(i) == Animation::TYPE_VALUE) {
|
||||
if (np.get_subname_count() == 0) {
|
||||
path_cache.push_back(Path());
|
||||
ERR_CONTINUE_MSG(np.get_subname_count() == 0, "Value Track lacks property: " + np + ".");
|
||||
}
|
||||
|
||||
} else if (animation->track_get_type(i) == Animation::TYPE_METHOD) {
|
||||
if (path.subpath.size() != 0) { // Trying to call a method of a non-resource
|
||||
|
||||
path_cache.push_back(Path());
|
||||
ERR_CONTINUE_MSG(path.subpath.size() != 0, "Method Track has property: " + np + ".");
|
||||
}
|
||||
}
|
||||
|
||||
path.valid = true;
|
||||
|
||||
path_cache.push_back(path);
|
||||
|
||||
if (!connected_nodes.has(path.node)) {
|
||||
connected_nodes.insert(path.node);
|
||||
path.node->connect("tree_exiting", callable_mp(this, &AnimationCache::_node_exit_tree), Node::make_binds(path.node), CONNECT_ONESHOT);
|
||||
}
|
||||
}
|
||||
|
||||
cache_dirty = false;
|
||||
cache_valid = true;
|
||||
}
|
||||
|
||||
void AnimationCache::set_track_transform(int p_idx, const Transform3D &p_transform) {
|
||||
if (cache_dirty) {
|
||||
_update_cache();
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(!cache_valid);
|
||||
ERR_FAIL_INDEX(p_idx, path_cache.size());
|
||||
Path &p = path_cache.write[p_idx];
|
||||
if (!p.valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef _3D_DISABLED
|
||||
ERR_FAIL_COND(!p.node);
|
||||
ERR_FAIL_COND(!p.node_3d);
|
||||
|
||||
if (p.skeleton) {
|
||||
p.skeleton->set_bone_pose(p.bone_idx, p_transform);
|
||||
} else {
|
||||
p.node_3d->set_transform(p_transform);
|
||||
}
|
||||
#endif // _3D_DISABLED
|
||||
}
|
||||
|
||||
void AnimationCache::set_track_value(int p_idx, const Variant &p_value) {
|
||||
if (cache_dirty) {
|
||||
_update_cache();
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(!cache_valid);
|
||||
ERR_FAIL_INDEX(p_idx, path_cache.size());
|
||||
Path &p = path_cache.write[p_idx];
|
||||
if (!p.valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(!p.object);
|
||||
p.object->set_indexed(p.subpath, p_value);
|
||||
}
|
||||
|
||||
void AnimationCache::call_track(int p_idx, const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
|
||||
if (cache_dirty) {
|
||||
_update_cache();
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(!cache_valid);
|
||||
ERR_FAIL_INDEX(p_idx, path_cache.size());
|
||||
Path &p = path_cache.write[p_idx];
|
||||
if (!p.valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(!p.object);
|
||||
p.object->call(p_method, p_args, p_argcount, r_error);
|
||||
}
|
||||
|
||||
void AnimationCache::set_all(float p_time, float p_delta) {
|
||||
if (cache_dirty) {
|
||||
_update_cache();
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(!cache_valid);
|
||||
|
||||
int tc = animation->get_track_count();
|
||||
for (int i = 0; i < tc; i++) {
|
||||
switch (animation->track_get_type(i)) {
|
||||
case Animation::TYPE_TRANSFORM3D: {
|
||||
Vector3 loc, scale;
|
||||
Quaternion rot;
|
||||
animation->transform_track_interpolate(i, p_time, &loc, &rot, &scale);
|
||||
Transform3D tr(Basis(rot), loc);
|
||||
tr.basis.scale(scale);
|
||||
|
||||
set_track_transform(i, tr);
|
||||
|
||||
} break;
|
||||
case Animation::TYPE_VALUE: {
|
||||
if (animation->value_track_get_update_mode(i) == Animation::UPDATE_CONTINUOUS || (animation->value_track_get_update_mode(i) == Animation::UPDATE_DISCRETE && p_delta == 0)) {
|
||||
Variant v = animation->value_track_interpolate(i, p_time);
|
||||
set_track_value(i, v);
|
||||
} else {
|
||||
List<int> indices;
|
||||
animation->value_track_get_key_indices(i, p_time, p_delta, &indices);
|
||||
|
||||
for (int &E : indices) {
|
||||
Variant v = animation->track_get_key_value(i, E);
|
||||
set_track_value(i, v);
|
||||
}
|
||||
}
|
||||
|
||||
} break;
|
||||
case Animation::TYPE_METHOD: {
|
||||
List<int> indices;
|
||||
animation->method_track_get_key_indices(i, p_time, p_delta, &indices);
|
||||
|
||||
for (int &E : indices) {
|
||||
Vector<Variant> args = animation->method_track_get_params(i, E);
|
||||
StringName name = animation->method_track_get_name(i, E);
|
||||
Callable::CallError err;
|
||||
|
||||
if (!args.size()) {
|
||||
call_track(i, name, nullptr, 0, err);
|
||||
} else {
|
||||
Vector<const Variant *> argptrs;
|
||||
argptrs.resize(args.size());
|
||||
for (int j = 0; j < args.size(); j++) {
|
||||
argptrs.write[j] = &args.write[j];
|
||||
}
|
||||
|
||||
call_track(i, name, (const Variant **)&argptrs[0], args.size(), err);
|
||||
}
|
||||
}
|
||||
|
||||
} break;
|
||||
default: {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationCache::set_animation(const Ref<Animation> &p_animation) {
|
||||
_clear_cache();
|
||||
|
||||
if (animation.is_valid()) {
|
||||
animation->disconnect("changed", callable_mp(this, &AnimationCache::_animation_changed));
|
||||
}
|
||||
|
||||
animation = p_animation;
|
||||
|
||||
if (animation.is_valid()) {
|
||||
animation->connect("changed", callable_mp(this, &AnimationCache::_animation_changed));
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationCache::_bind_methods() {
|
||||
}
|
||||
|
||||
void AnimationCache::set_root(Node *p_root) {
|
||||
_clear_cache();
|
||||
root = p_root;
|
||||
}
|
||||
|
||||
AnimationCache::AnimationCache() {
|
||||
}
|
||||
@ -1,84 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* animation_cache.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef ANIMATION_CACHE_H
|
||||
#define ANIMATION_CACHE_H
|
||||
|
||||
#include "scene/3d/skeleton_3d.h"
|
||||
#include "scene/resources/animation.h"
|
||||
|
||||
class AnimationCache : public Object {
|
||||
GDCLASS(AnimationCache, Object);
|
||||
|
||||
struct Path {
|
||||
RES resource;
|
||||
Object *object = nullptr;
|
||||
#ifndef _3D_DISABLED
|
||||
Skeleton3D *skeleton = nullptr;
|
||||
Node3D *node_3d = nullptr;
|
||||
#endif // _3D_DISABLED
|
||||
Node *node = nullptr;
|
||||
|
||||
int bone_idx = -1;
|
||||
Vector<StringName> subpath;
|
||||
bool valid = false;
|
||||
};
|
||||
|
||||
Set<Node *> connected_nodes;
|
||||
Vector<Path> path_cache;
|
||||
|
||||
Node *root = nullptr;
|
||||
Ref<Animation> animation;
|
||||
bool cache_dirty = true;
|
||||
bool cache_valid = false;
|
||||
|
||||
void _node_exit_tree(Node *p_node);
|
||||
|
||||
void _clear_cache();
|
||||
void _update_cache();
|
||||
void _animation_changed();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_track_transform(int p_idx, const Transform3D &p_transform);
|
||||
void set_track_value(int p_idx, const Variant &p_value);
|
||||
void call_track(int p_idx, const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
|
||||
|
||||
void set_all(float p_time, float p_delta = 0);
|
||||
|
||||
void set_animation(const Ref<Animation> &p_animation);
|
||||
void set_root(Node *p_root);
|
||||
|
||||
AnimationCache();
|
||||
};
|
||||
|
||||
#endif // ANIMATION_CACHE_H
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue