-
-
Notifications
You must be signed in to change notification settings - Fork 21.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve global bone pose calculation in Skeleton3D
#97538
Improve global bone pose calculation in Skeleton3D
#97538
Conversation
Tested on Animation_test.zip.
As for thread safe (as I understand it you are talking about using the |
c86266b
to
bd70bc1
Compare
I was wondering if there is a problem now that the logic is more complex. But if the scene tree is not multi-threaded then that's ok I guess. |
As far as I know multi-threaded scene tree is implemented. I'm unable to get you the details, but it was done in an earlier release disabled by default. |
Right, the implementation is here tho, it would be cool in look in this for skeleton, anim player/tree multithreading improvements. #75901 |
Is this ready for review? I noticed it is still in draft stage but all the items are checked. |
Yes, I forgot. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have tested PhysicalBone (#96270), Retarget (#97824) and some IK, it looks good as it is working fine.
I appreciate that you send this PR as this was one of the task of our todo list, as I commented in #92931 (comment), thanks.
bd70bc1
to
9ab8488
Compare
Fixed conflicts. |
Thanks! |
@detomon Do you think this can be done to the general 3d node caching system too? |
@fire I'm not too familiar with how the Node3D hierarchy works. I will look into that. |
This change introduces a way to calculate global bone poses without recalculating all bones every time a pose changes. It defines the bone hierarchy as a nested set. This makes it possible to represent bone subtrees continuously within an array. With regard to the introduction of
SkeletonModifier3D
, this should improve performance when using many modifiers that depend on global poses.Two fields are added to
Skeleton3D::Bone
:nested_set_offset
: defines the position within the nested set1nested_set_span
: defines the size of the subtree (the bone itself and all descendants)This shows the nested set values for a simplified skeleton:
How it works
Skeleton3D::bone_global_pose_dirty
is an array containing a flag for each bone indicating whether the global pose needs to be recalculated. It can be indexed withBone::nested_set_offset
, followed by the descendant bones.When changing the pose of a bone, the dirty flags of its subtree need to be set to indicate that the global poses of the bone and its descendants need to be recalculated. This is done by setting all flags in the range from
Bone::nested_set_offset
with lengthBone::nested_set_span
totrue
. This has some overhead2. But it can be skipped if the bone is already dirty at indexBone::nested_set_offset
. Because if a global pose of a bone is dirty, all of its descendants are dirty too.Getting the global pose with
get_bone_global_pose
When requesting the global pose of a bone, only the global poses of its parents that are dirty are recalculated and the dirty flag is cleared. In the best case (if the parent global poses have already been calculated) only a few global poses need to be recalculated.
Recalculating global poses with
force_update_bone_children_transforms
By looping through
Skeleton3D::nested_set_offset_to_bone_index
it is possible to update the bone hierarchy without the need for recursion. By checking the dirty flag at the current index, only required bones are updated. The order also ensures, that parent bone poses are calculated before child bone poses.Benchmarks
skeleton_3d.gd.zip
Note: I ran the tests individually. Some values were way too high even on
master
when run in series.TODO
get_bone_global_pose
force_update_bone_children_transforms
Footnotes
For imported scenes,
nested_set_offset
seems to be the same as the bone index. Presumably bones are already ordered this way. However, this may be different for manually created skeletons. ↩It could be implemented as some kind of bit field structure instead of an array, if it turns out that performance is a problem at that point. ↩