-
-
Notifications
You must be signed in to change notification settings - Fork 21.5k
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
AnimationTree: Improper blending of bone location when blending more than two animations #46038
Comments
More experimentation: |
I've discovered the bug is related to the order in which
I will investigate further tomorrow |
I don't believe so. This issue occurs the same even if the animations are the same length, so I don't think it's related to syncing, and I'm not doing anything with Add2 or Add3. |
Probably #34134 |
@TokageItLab That seems exactly it! I'll pull that branch and see if it works for me. |
@needleful Can you open issue about #34134 (comment) separately from #34134? I think that it seems to be a StateMachine issue, separate from the blending issue. |
I'm not sure if this is the exact same issue as what I've been having, but it seems likely related to an issue I noticed where there's some inconsistency in the way that the BlendSpace2D grid interpolates animations. I've created a test app in Godot 4 Alpha, but the same issue has been present in previous 3.x releases. BlendSpace2DIssue.mp4All three boxes are attempts to interpolate between three single-keyframe animations using a 2D Blend Space. Each animation is meant to Notice that at the corners they all correctly position and scale the boxes, however they don't line up at points along the edges or within the triangle. The red box is when the position and scale are animated using the special 3D Position and 3D Scale tracks. The green box is when the position and scale are animated using property tracks. The blue box was programmed manually in a GDScript tool file that calculates barycentric coordinates and then blends the three animations in that ratio. The blue box is what I think most people would expect. You can see the problem numerically if you place the blend position in the grid to (0, .333), which is the center of mass of the blend space's triangle. At this point, each animation should have equal influence over the resultant transformation, which will be true for the blue box, but not for the green or red box. I have a fix for it here. If it seems good enough I'll make a PR out of it but I likely haven't thoroughly tested it. |
Thanks for the quick reply. I just finished cloning the branch you linked, and after building it and rerunning that same project, I'm unfortunately still getting blending issues: BlendSpace2DIssue2.mp4Can you confirm that the same result happens on your environment? |
@Shnazzy We already know that there are two major problems. The first thing is that the current Godot 4.0 blending 3D transform is perfectly broken. The second is that there is inconsistency in the results depending on the blend order. See this comment. #54205 fixes the first issue (deference between red and green) but doesn't fix second issue (deference between red and blue, jump the values when cross triangle border problem). For second issue, as I mentioned in my comment, we probably have to change the blend stack and change the way of blending with triangle in order to have consistent blend results for all cases. And I think we need to separate those issues first. BTW, in 4.0, modifying Transform3D by property tracks is deprecated for performance reason. |
@TokageItLab Understood. For what it's worth though, the commit I linked fixed the triangle blending issue on my end (at least in the simple case I implemented). |
@Shnazzy I tested it more. Your commit has the potential to get things right, but there are a few things to consider on how to implement it.
I'll discuss these with @reduz, @fire, @SaracenOne and @lyuma once. We can help you if you want to create a PR, or you can let us do it for you. |
@TokageItLab I'm not interested in credit or attention. I'd say besides the value types that I gave attention to in the test project, I really don't know much about the other track and property types. Rotation, for instance, I'd have to test it some more to determine if the same problems happen. It probably also depends on quaternions vs. eulers. I'll take a look at the other track types, but you're free to do what you want with the changes to apply them to other components. |
@Shnazzy To be honest, I'm not sure why your fix is working correctly. I will look into this further, but we need a complete mathematical explanation of what is going on. It looks like you are fixing a problem related to the initial values of the branches increased by the blend, but when I do the same fix for Quaternion, rotation tries to go through the initial values of Quaternion instead of the shortest path, so the Quaternions (e.g. Y: 179deg & Y: -179deg in Euler) are not interpolated correctly. Edited: 2022-02-05.15.29.54.mov |
Okay I did some more experimenting. Try this: rot_raw needs to be added to the t structure's definition. It's just an accumulator that can be accumulated without normalizing until the very end. t->rot becomes the normalized version of rot_raw while avoiding any mid-step interpolation math. Edit: |
@Shnazzy Excellent! Looks like it is complementing correctly. Perhaps the root motion needs a separate initialization and rot_accum is no longer needed, so I think the final fix will look like this. |
@Shnazzy However, I suspect that if it normalize by adding each element of the quaternion as it is, it may have problems with large movements. There is similar experiment #40592 (comment). |
A few things:
|
Using slerpni() instead of slerp() may solve the interpolation problem in Quaternion. Therefore, it seems that neither accumulator nor rot_raw is necessary. I will do some more testing on the initialization. There was a problem with infinitely large scales when not all values were initialized in each tracks. |
To elaborate more on why the math of blend works and why lerp doesn't: Points A, B, C have weights wA, wB, wC in the current blending step. Call the current accumulated point P. Lerp Math (Old way): lerp(P1, P2, b) = P1 * (1 - b) + P2 * b First iteration (A) is made the initial value of P. (As a side note, if it were just two nodes, A and B, then this would be accurate since wB being .49 would imply wA is .51) Next iteration (C): Thus, C's blending is correct, but A and B look way off. Blend Math (new way): blend(P1, P2, b) = P1 + P2 * b This should work with scale and position since they are linear spaces. As for slerp and quaternions, I think since quaternions aren't linear vector spaces (can't multiply a quat by a scalar value, can't add two quats together) it can't work the same way. It's sort of like how coordinates on a sphere won't follow the same geometric rules as those on a flat surface. |
By setting the initial value of each track to a fixed value, for example if animation A has a PositionTrack and animation B does not have a PositionTrack, the object to which A's PositionTrack is assigned will force the following value in animation B Vector3(0,0,0), it's odd. In 3.x and #54205, the initial value is set to the original pose, so nothing happens. Assuming a new fix is needed in blending, but we need to fix that problem. |
I don't think there's a "right" answer to "what should the blend triangle do to A if A doesn't have a track like B and C do?" One answer would be to make A to default to the identity transform. Another option is to find some way to have B and C act as if the weight distribution was only between them. As another option, there could be a "Default Tracks" animation like the reset track, or perhaps use the reset track if it's available... |
If we choose way of the using default ID Transform, we get the problem of odd poses in character models. I believe that at least that should be the implementation that uses the latter RESET track. |
I tested that to implement init_loc, init_rot, init_scale to TRSTracks with Skeleton and bone_rest. For blendshape/property/bezier track, we need to do same thing with using RESET track. Off course if TRSTracks have RESET track, it should use RESET track even if it has bone_rest. |
Well here's something I found: Also the resource I found here might be of use if it's not already been looked at. |
Godot version:
Godot 3.2.4 rc1
OS/device including version:
Windows 10 version 1909
Issue description:
When blending more than two animations using two separate Animation Nodes (such as a Blend2 being consumed by another Blend2), the location of bones isn't properly interpolated if more than 2 animations are being blended together.
This is most noticeable when transitioning from a Blend Amount less than 1 to exactly 1, which causes a noticeable "snapping", because values arbitrarily close to 1 have a noticeably different location. It seems rotations are interpolated smoothly.
I've also tested this with a BlendSpace2D within a BlendSpace1D, and using transitions to have a similar effect. Both have the same problem, where there's a jarring transition when reaching an animation.
However, here's a strange exception: if the blended node is put into the
in
slot of a Blend2 and the third animation theblend
slot, it works fine.video of the problem
Steps to reproduce:
in
slot to use the third, non-translated animation, and setblend
to the translated animation blend.in
andblend
inputs, the problem goes away in this example. This could be a useful workaround, unless you're blending between two blending nodes, which is my real use case, in which case the issue is present regardless of the input order).Minimal reproduction project:
project.zip
Things to do in this project:
problem_blend
from 0 to 1. The box will snap when going from 0.99 to 1 and back.down
to 0 or 1 and repeat the previous step. The problem disappearsin
andblend
forproblem_blend
and repeat step 1. The problem disappearsThe text was updated successfully, but these errors were encountered: