godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
88.71k stars 20.12k forks source link

2D Inverse Kinematics do not work when parent node has negative X Scale #75224

Open severedskullz opened 1 year ago

severedskullz commented 1 year ago

Godot version

4.0.1 Mono

System information

Windows 10

Issue description

When a Node2D has its scale set to -1 on the X axis to flip the rig, IK no longer correctly paths to its targets. This happens for all types of IK Skeleton Modifications.

In the attached example, I have a TwoBoneIK, and a LookAt which should be positioned on top of the logo.

With a basic rig an a Normal Scale (1,1): image

With a basic rig on a Flipped Scale (-1,1): image

Steps to reproduce

Create a basic Skeleton2D Rig, Apply any SkeletonModification2D* onto it, and then flip the parent's X scale to -1.

Minimal reproduction project

SkeletonIKTest.zip

severedskullz commented 1 year ago

It should also be noted that the bone's child sprites do not appear to be flipped when this issue occurs. I believe this to be a side effect of whatever is going on with the scale here, which should also be solved with this IK issue is resolved.

HeadMonitor commented 1 year ago

Any update on this? Any temporary solution?

NonRidiculousAdjective commented 1 year ago

Any update on this? Any temporary solution?

Did you manage to find one?

HeadMonitor commented 1 year ago

Any update on this? Any temporary solution?

Did you manage to find one?

Unfortunately there doesn't seem to be one. I tried everything I could. We have to wait till the bug is patched. 😞

I can still continue making my game, it's just gonna be slightly harder for my animator to do her job but ehhh what can you do.

NonRidiculousAdjective commented 1 year ago

Any update on this? Any temporary solution?

Did you manage to find one?

Unfortunately there doesn't seem to be one. I tried everything I could. We have to wait till the bug is patched. 😞

I can still continue making my game, it's just gonna be slightly harder for my animator to do her job but ehhh what can you do.

I see, but thank you for the quick reply!

severedskullz commented 1 year ago

I managed to find a third party library that implemented their own custom IK which solves the issue, but comes with its own issues. Some of the IK seems to be offset from the target position, and some of the different chains perform strangely / inconsistently but at the very least, negative scaling works.

https://twistedtwigleg.itch.io/twistedik2

severedskullz commented 1 year ago

Why Git puts a button to close the issue with a comment adjacent to the actual comment button with focus before said comment button I will never understand. Apologies for the closure/reopening

HeadMonitor commented 1 year ago

I managed to find a third party library that implemented their own custom IK which solves the issue, but comes with its own issues. Some of the IK seems to be offset from the target position, and some of the different chains perform strangely / inconsistently but at the very least, negative scaling works.

https://twistedtwigleg.itch.io/twistedik2

Yeah I came across that in my search but I prefer using as little third party libraries as possible. Thanks for sharing though. Hopefully they fix this in 4.1 or 4.2.

pdorok commented 1 year ago

Hello, everybody.

I have the exact same issue in my own project with a 2D character with a Skeleton2D and SkeletonModification2DTwoBoneIK for its legs.

The IK Targets are not flipped correctly, when setting scale.x to -1 to flip the character. I attached a red orb sprite to the left leg IK target and a green orb sprite to the right leg IK target for debugging: I could clearly see that the flipping was messed up and the animations didn't play correctly in the flipped direction, i.e. were offset by the wrong flip of the IK Targets.

However, my level includes the following code to restart the level scene, when the player character has fallen to deep.

if the_player.position.y > 2000:
    get_tree().reload_current_scene()

After the scene was reloaded once via get_tree().reload_current_scene() because the player character had fallen too deep, the flipping actually WORKED as intended... So, the IK Targets were only messed up during the initial run of the level, until the level was restarted via script in runtime.

flipthebird1

If there is any news on this issue, please feel free to share it.

Thank you very much for your time and happy developing!

anyo1 commented 1 year ago

how do we know when the bug will be patched?

Wiesterfeler commented 1 year ago

Yes this bug is very annoying and makes reverse kinematic completely useless, any chance we can see it being push as a priority fix?

fouf commented 1 year ago

Encountering this bug, trying to find a temporary solution...

Maaack commented 1 year ago

I've recreated the issue with Godot 4.1 as well.

The editor gizmos showing bending constraints flipped correctly, but in dragging the target in the editor, the bones themselves moved in the opposite direction.

image

In our case, we may be able to workaround it by creating different instances for left and right with custom constraints for each. This will be a hindrance in scaling IK work, though.

JumboDS64 commented 1 year ago

Any update on this? Any temporary solution?

Did you manage to find one?

Unfortunately there doesn't seem to be one. I tried everything I could. We have to wait till the bug is patched. 😞

I can still continue making my game, it's just gonna be slightly harder for my animator to do her job but ehhh what can you do.

My solution was to render the IK'd skeleton in a separate SubViewport, render that viewport as the entity's 2D ViewportTexture sprite, and flip the SPRITE rather than the skeleton model: the issue Not a perfect solution, especially since it makes it harder to track the IK with other entities (I'm only using IK to make animations such as idling look nicer), but a little code to synchronize points in the subviewport with the other entities would probably work well enough.

thiagola92 commented 1 year ago

EDIT: Did not work for others cases, sadly still waiting for ~godot~ a solution.

~I don't know if this can help somebody debug the problem but here what i'm trying:~

func _on_button_pressed() -> void:
    scale.x *= -1 # Normal flip

    var modification_stack: SkeletonModificationStack2D = skeleton.get_modification_stack()

    for idx in modification_stack.modification_count:
        var modification = modification_stack.get_modification(idx)

        if modification is SkeletonModification2DTwoBoneIK:
            var node_path: NodePath = modification.get_joint_one_bone2d_node()
            var bone2d: Bone2D = skeleton.get_node(node_path)

            bone2d.scale.y *= -1
            modification.flip_bend_direction = not modification.flip_bend_direction

~Don't know if this works for every single situation, but here is a test doing random moves:~

Screencast from 2023-08-01 16-41-32.webm

ScottHo commented 7 months ago

I found a somewhat sane solution. You can flip the parents scale, but then flip all the joints as well. Then select/unselect the Flip Bend Direction on the IK Mod.

Skeleton2D's parent has a scale of (1,1) and (-1,1) LeftShoulder has a scale of (1,1) and (1,-1) The IK Mode has Flip Bend Direction enabled for one but not the other

image

image

kondelik commented 2 months ago

I think this is a duplicate of #80252 (+ there is a temp fix via script)