Fix #111553: Double IK constraint not working #113056

Merged
Christoph Lendenfeld merged 5 commits from ChrisLend/blender:fix_double_ik_constraint into blender-v4.0-release 2023-10-10 09:06:37 +02:00

It seems that the code only ever converted the first IK constraint found into a PoseTree.
Before #110417 constraints with zero influence were skipped so it worked, except for the bug with the depsgraph.

After this patch the logic is the following:
From top to bottom of the constraint stack, keep adding constraints until the first constraint with influence is added.

This ensures, that if there is only one disabled constraint,
it still gets converted into a PoseTree,
which is needed for the depsgraph to work correctly.

The resulting behavior from adding the first active constraint is
that the higher in the stack the constraint is, the higher its priority.

To achieve that I split off a helper function find_ik_constraints
that populates a vector of bConstraint pointers.
The code to create the PoseTree is still largely the same,
except I moved a few variables closer to where they are used.


I made sure the code doesn't reintroduce the issue from #88752: Setting an overlapping IK constraint to zero influence/disabled gives weird behavior

It seems that the code only ever converted the first IK constraint found into a `PoseTree`. Before #110417 constraints with zero influence were skipped so it worked, except for the bug with the depsgraph. After this patch the logic is the following: From top to bottom of the constraint stack, keep adding constraints until the first constraint with influence is added. This ensures, that if there is only one disabled constraint, it still gets converted into a `PoseTree`, which is needed for the depsgraph to work correctly. The resulting behavior from adding the first active constraint is that the higher in the stack the constraint is, the higher its priority. To achieve that I split off a helper function `find_ik_constraints` that populates a vector of `bConstraint` pointers. The code to create the `PoseTree` is still largely the same, except I moved a few variables closer to where they are used. ------ I made sure the code doesn't reintroduce the issue from [#88752: Setting an overlapping IK constraint to zero influence/disabled gives weird behavior](https://projects.blender.org/blender/blender/issues/88752)
Christoph Lendenfeld added the
Module
Animation & Rigging
label 2023-09-29 13:02:55 +02:00
Christoph Lendenfeld added 1 commit 2023-09-29 13:03:09 +02:00
Christoph Lendenfeld added 1 commit 2023-09-29 14:20:07 +02:00
Christoph Lendenfeld requested review from Brecht Van Lommel 2023-09-29 14:26:04 +02:00
Christoph Lendenfeld requested review from Nathan Vegdahl 2023-09-29 14:26:04 +02:00
Christoph Lendenfeld changed title from WIP: Fix #111553: Double IK constraint not working to Fix #111553: Double IK constraint not working 2023-09-29 14:26:15 +02:00

From the description this sounds like it would break tree IK setups, where multiple IK constraints are set up to solve for multiple targets simultaneously?

From the description this sounds like it would break tree IK setups, where multiple IK constraints are set up to solve for multiple targets simultaneously?

From #111553 (comment) I understand that the problem happens with multiple IK constraints on a single bone? If that's the case I would expect only one of the constraints to be used, as it's not possible for a single bone to hit two targets.

Though you could simultaneously solve one location and one rotation constraint.

From https://projects.blender.org/blender/blender/issues/111553#issuecomment-1010316 I understand that the problem happens with multiple IK constraints on a single bone? If that's the case I would expect only one of the constraints to be used, as it's not possible for a single bone to hit two targets. Though you could simultaneously solve one location and one rotation constraint.
Author
Member

From #111553 (comment) I understand that the problem happens with multiple IK constraints on a single bone? If that's the case I would expect only one of the constraints to be used, as it's not possible for a single bone to hit two targets.

Though you could simultaneously solve one location and one rotation constraint.

Depends, if none of them have full influence, a mix between them is the expected result.
If there is an IK constraint with full influence it would override any previous constraints.
e.g.
image

> From https://projects.blender.org/blender/blender/issues/111553#issuecomment-1010316 I understand that the problem happens with multiple IK constraints on a single bone? If that's the case I would expect only one of the constraints to be used, as it's not possible for a single bone to hit two targets. > > Though you could simultaneously solve one location and one rotation constraint. Depends, if none of them have full influence, a mix between them is the expected result. If there is an IK constraint with full influence it would override any previous constraints. e.g. ![image](/attachments/df60b226-9bb4-4e2e-ae7e-b793155cd72a)
203 KiB

Ok, that makes sense. But then how do you decide which IK constraints get solved together for tree IK?

Ok, that makes sense. But then how do you decide which IK constraints get solved together for tree IK?
Author
Member

Ok, that makes sense. But then how do you decide which IK constraints get solved together for tree IK?

tbh I had to look up what tree IK does, but a quick test showed that there is no difference in behavior with this PR using Tree-IK
I've attached my test file just in case.

I think because the PoseTree is saved on the pose channel root, it works just the same.
So the first constraint would evaluate and add it's PoseTree to the root bone, and the second would find that tree and insert itself just as before

> Ok, that makes sense. But then how do you decide which IK constraints get solved together for tree IK? tbh I had to look up what tree IK does, but a quick test showed that there is no difference in behavior with this PR using Tree-IK I've attached my test file just in case. I think because the `PoseTree` is saved on the pose channel root, it works just the same. So the first constraint would evaluate and add it's `PoseTree` to the root bone, and the second would find that tree and insert itself just as before

Imagine you have two bones (A and B) each with two IK constraints (0 and 1). And these all share the same root bone. Now which constraints are going to be solved together (= put into the same pose tree)?

With non-zero influence for all constraints it seems to be:

  • Previously: A0 + B0, A1 and B1 ignored.
  • This PR: A0 + B0 and A1 + B1.

And then when you change the influence to zero, you can get many different combinations. It's can be confusing either way, but more so with this new behavior I think, since there are many more combinations. You could for example end up with A0 + B1 and A1.

I don't really have a good short term solution for this though. This would be more clear with node based constraints, where you could have one node per pose tree.

Imagine you have two bones (A and B) each with two IK constraints (0 and 1). And these all share the same root bone. Now which constraints are going to be solved together (= put into the same pose tree)? With non-zero influence for all constraints it seems to be: * Previously: A0 + B0, A1 and B1 ignored. * This PR: A0 + B0 and A1 + B1. And then when you change the influence to zero, you can get many different combinations. It's can be confusing either way, but more so with this new behavior I think, since there are many more combinations. You could for example end up with A0 + B1 and A1. I don't really have a good short term solution for this though. This would be more clear with node based constraints, where you could have one node per pose tree.
Brecht Van Lommel approved these changes 2023-09-29 18:19:26 +02:00
Member

Christoph asked me to comment on this, so I'll try, but I don't have much I'm afraid.

I can't really conjure a use case where I want to mix the results of 2 IK constraints, and I'm not sure what exactly I would expect from that.
Having >1 IK constraints seems reasonable as long as only one of them is active at a time (whether due to influence or enabled flag), so you can switch between different targets. But wanting to mix the two is probably a problem with several valid solutions, and it's difficult to argue that any is better or worse than any other. That said, I've got nothing against just picking one solution that seems reasonable and supporting that.

Only one thing I'd want to confirm: Do things still behave in some expected way if the chain length value isn't the same between the two constraints?

Christoph asked me to comment on this, so I'll try, but I don't have much I'm afraid. I can't really conjure a use case where I want to mix the results of 2 IK constraints, and I'm not sure what exactly I would expect from that. Having >1 IK constraints seems reasonable as long as only one of them is active at a time (whether due to influence or enabled flag), so you can switch between different targets. But wanting to mix the two is probably a problem with several valid solutions, and it's difficult to argue that any is better or worse than any other. That said, I've got nothing against just picking one solution that seems reasonable and supporting that. Only one thing I'd want to confirm: Do things still behave in some expected way if the chain length value isn't the same between the two constraints?
Author
Member

Only one thing I'd want to confirm: Do things still behave in some expected way if the chain length value isn't the same between the two constraints?

Good question. It does behave differently now. In fact it is now quite broken if both constraints are active
image
I think that is because the PoseTree now lands on a different root, so they get evaluated separately so the evaluation can't be skipped for either of them.
So what is the expected behavior in this case?

> Only one thing I'd want to confirm: Do things still behave in some expected way if the chain length value isn't the same between the two constraints? Good question. It does behave differently now. In fact it is now quite broken if both constraints are active ![image](/attachments/1b2bedc3-76c2-4488-8859-aa0e72f535a4) I think that is because the `PoseTree` now lands on a different root, so they get evaluated separately so the evaluation can't be skipped for either of them. So what is the expected behavior in this case?
319 KiB

In fact it is now quite broken if both constraints are active

What is broken? I can't tell from the screenshot or testing here.

I think that is because the PoseTree now lands on a different root, so they get evaluated separately so the evaluation can't be skipped for either of them.

This PR makes the constraints get evaluated separately even when they share the same root, why would evaluating them separately for different roots be a problem?

> In fact it is now quite broken if both constraints are active What is broken? I can't tell from the screenshot or testing here. > I think that is because the PoseTree now lands on a different root, so they get evaluated separately so the evaluation can't be skipped for either of them. This PR makes the constraints get evaluated separately even when they share the same root, why would evaluating them separately for different roots be a problem?
Member

So what is the expected behavior in this case?

Great question... Could leave the problem un-solved and limit each constraint to the lowest chain length in the stack, and draw a warning for any constraint that exceeds that? At least, until someone can conjure up a legitimate use case, and with it, the expected behaviour.

> So what is the expected behavior in this case? Great question... Could leave the problem un-solved and limit each constraint to the lowest chain length in the stack, and draw a warning for any constraint that exceeds that? At least, until someone can conjure up a legitimate use case, and with it, the expected behaviour.
Author
Member

attached a video to show the issue better.
It only happens when the longer chain is second in the constraint stack.

The execution order of trees seems to be determined by the order they are added in. The top constraint is always evaluated first.
So if the constraint with the shorter chaing is first, it evaluates two bones, setting the POSE_DONE flag on them.
This flag stops the evaluation of the IK for the second constraint, but only on those two bones. So bending the third bone will make it point the wrong way.

As to why it glitches and jumps around like that, I am not sure. Is this an issue with the depsgraph again?

attached a video to show the issue better. It only happens when the longer chain is second in the constraint stack. The execution order of trees seems to be determined by the order they are added in. The top constraint is always evaluated first. So if the constraint with the shorter chaing is first, it evaluates two bones, setting the `POSE_DONE` flag on them. This flag stops the evaluation of the IK for the second constraint, but only on those two bones. So bending the third bone will make it point the wrong way. As to why it glitches and jumps around like that, I am not sure. Is this an issue with the depsgraph again?
Christoph Lendenfeld added 3 commits 2023-10-06 10:58:21 +02:00
Author
Member

@brecht I think I found a proper solution, please check again before I land this. The logic is the following.

From top to bottom of the constraint stack, keep adding constraints until the first constraint with influence is added.
This is what is needed to ensure the previous issue doesn't come back, because inactive constraints still need to be made into a PoseTree for the depsgraph to work.
By doing it that way, it is also consistent with 3.6 where the first found active constraint is the one that evaluates.
No more mixing of IK constraints.

I've checked the test file from #88752 to ensure the issue doesn't return, and I've checked the Tree IK functionality still works as in 3.6

@brecht I think I found a proper solution, please check again before I land this. The logic is the following. **From top to bottom of the constraint stack, keep adding constraints until the first constraint with influence is added.** This is what is needed to ensure the previous issue doesn't come back, because inactive constraints still need to be made into a `PoseTree` for the depsgraph to work. By doing it that way, it is also consistent with 3.6 where the first found active constraint is the one that evaluates. No more mixing of IK constraints. I've checked the test file from #88752 to ensure the issue doesn't return, and I've checked the Tree IK functionality still works as in 3.6
Christoph Lendenfeld requested review from Brecht Van Lommel 2023-10-06 11:05:28 +02:00
Brecht Van Lommel approved these changes 2023-10-06 18:12:02 +02:00
Brecht Van Lommel left a comment
Owner

Seems to work fine in my tests.

Seems to work fine in my tests.
Christoph Lendenfeld merged commit 0c2afa7c17 into blender-v4.0-release 2023-10-10 09:06:37 +02:00
Christoph Lendenfeld deleted branch fix_double_ik_constraint 2023-10-10 09:06:41 +02:00
Sign in to join this conversation.
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
3 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#113056
No description provided.