No reviewers
Labels
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset System
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
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
Viewport & EEVEE
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Asset Browser Project
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
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
Module
Viewport & EEVEE
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Severity
High
Severity
Low
Severity
Normal
Severity
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
4 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: blender/blender#108134
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "himisa/blender:main"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixed armature deformation bug when in Preserve Volume mode and both scale & rotation is present.
The problem:
Why this happens:
This happens because the Preserve Volume mode internally uses Quaternion to interpolate rotations.
A bone has 3 parts of data describing its deformation: Quaternion(w,x,y,z) rotation
quat
, Translation(w,x,y,z)trans
, and Scaling(4x4 matrix)scale
. To calculate deformed position of a vertexr
, it will be firstly scaled byscale
, then rotated and translated byquat & trans
.The 4x4 scaling matrix
scale
has a 3x3 partS33
about scaling and shearing along 3 axes, and a vector partST3
that further translate the scaled position. i.e.scale@r = S33@r + ST3
. This enables scaling about an arbitrary "pivot" (a pointr0
satisfiesscale@r0 = r0
).However, when blending influence of multiple bones, different bones have different scaling pivot (their head position). Since quaternion rotation and translation/scaling are not mutable operations, this is what I believe causing this bug.
How this is fixed:
Note that the translational part
ST3
of the scaling matrix is redundant in functionality with Translational parttrans
in deformation data. There exists an equivalence transformation that simultaneously changetrans
andST3
, while keeping the deformation unchanged.I applied this equivalence transformation to move the pivot to the vertex that the bones are deforming, before blending multiple bone transformations. Note that now the vertex is the pivot, so scaling transformations will not change its position. Further blending/applying of scaling matrices can be avoided.
3982f2ddf9
2652043889Fix #32022, #43188, #100373to Fix #32022, #43188, #100373, Armature modifier - Preserve volume + ScaleI tested this PR out, and although it does indeed solve the uniformly-scaling-all-bones problem, I don't think it's the "proper" fix that we ideally want.
For example, with this PR when two bones are scaled differently, there's an asymmetry in how that affects the deformations depending on the direction of the bones. Here's an example (made with this PR) demonstrating this, with a comparison to linear blend skinning in the same situation:
scaling_asymmetry.blend
In this image the upper bone in all four examples has been scaled down. The linear blend skinning doesn't care about the direction of the bones. And ideally that's what we want from dual quaternion skinning as well.
Nevertheless, maybe this is still worth merging as a stop-gap solution...? Because it at least resolves the most egregious case. But it would be nice to have a full, proper solution that makes scaling with dual quaternion skinning actually fully well behaved.
A couple more things I noticed with additional testing of the PR:
So all-in-all, it looks to me like this approach is perhaps a bit of a workaround that only narrowly addresses one specific case: all bones being uniformly scaled by the same factor.
And again, maybe that's worth merging as a stop-gap. But, also again, having a proper solution that makes all scaling/shearing situations well behaved is ultimately what we want.
@himisa Also, if we do decide to merge this, the PR description probably needs to be fleshed out first. The attached image and blend file are definitely helpful and appreciated, but those wouldn't make it into the final commit log, which also needs to clearly communicate what is being fixed, etc.
@nathanvegdahl
( This is a quick fix that solved my problem when I'm rigging my character... )
I will further investigate whether the non-uniform scaling/shearing can also be fixed. It may take some time.
Fix #32022, #43188, #100373, Armature modifier - Preserve volume + Scaleto WIP: Fix #32022, #43188, #100373, Armature modifier - Preserve volume + ScaleWIP: Fix #32022, #43188, #100373, Armature modifier - Preserve volume + Scaleto Fix #32022, #43188, #100373, Armature modifier - Preserve volume + ScaleI examined the non-uniform scaling/shearing cases and found no clue about how they can be fixed.
The idea of this fix is explained in PR description, and is very simple and intuitive: align the pivot of all scaling transforms before blending. This solution does not care about whether the scaling is uniform or not. So, it also does not provide any clue for me to find what's going wrong in non-uniform scaling case. Thus, I conclude that the remaining absurdity may be the indeed limitation of quaternion interpolation, and an 'ideally proper fix' is beyond the scope of this PR. This statement is also true for asymmetries about bone direction.
I think this PR is ready for merge.
a3aea691bf
f6a94de0ebFix #32022, #43188, #100373, Armature modifier - Preserve volume + Scaleto WIP: Fix #32022, #43188, #100373, Armature modifier - Preserve volume + ScaleThe worst problem of this PR is it make some cases worse when both the bone and object vertices are offset from origin of their objects...
This make it unacceptable to merge at this point, and must be fixed...
@nathanvegdahl
I found a new way to reset pivot (set it to the vertices that bones are deforming), such that all the issues we have found are addressed.
This must be the ideal perfect fix.
Happy.
WIP: Fix #32022, #43188, #100373, Armature modifier - Preserve volume + Scaleto Fix #32022, #43188, #100373, Armature modifier - Preserve volume + Scale@ -63,2 +63,4 @@
if (dq_accum) {
BLI_assert(!co_accum);
/* FIX https://projects.blender.org/blender/blender/issues/32022 */
Instead of
FIX
I thinkWORKAROUND
is more appropriate here, because it's not a fully general solution, and only addresses certain cases.EDIT: ah! Just noticed that you updated the solution. (Sorry about that.) I'll do some additional testing. "FIX" might actually be appropriate now. Thanks for your work on this!
EDIT 2: just did some more testing, and although there are some extreme cases that still could be improved, I think "FIX" is fine for this because it does address the large majority of issues.
@ -65,0 +67,4 @@
DualQuat mdq;
if (deform_dq->scale_weight) {
float dst[3];
memcpy(&mdq, deform_dq, sizeof(DualQuat));
I think the
memcpy()
can be replaced with the simpler:(Unless I'm misunderstanding something.)
@ -65,0 +70,4 @@
memcpy(&mdq, deform_dq, sizeof(DualQuat));
mul_v3_m4v3(dst, mdq.scale, co_in);
sub_v3_v3(dst, co_in);
float w = mdq.quat[0], x = mdq.quat[1], y = mdq.quat[2], z = mdq.quat[3];
I think it's already fairly obvious that
mdq.quat[i]
are the wxyz components of the quaternion, so I'd say get rid of the temporary variables and just usemdq.quat
directly.I just want to avoid repeating
mdq.quad[
for 12 times.@ -65,0 +76,4 @@
mdq.trans[2] += .5f * (w * dst[1] + z * dst[0] - x * dst[2]);
mdq.trans[3] += .5f * (w * dst[2] + x * dst[1] - y * dst[0]);
mdq.scale_weight = 0.f;
deform_dq = &mdq;
deform_dq
is declaredconst
, so it feels like bad form to modify its pointer. I think it would be better to get rid of this assignment entirely, and just usemdq
directly below.const Type *ptr = &value
means the content ofvalue
shall not be changed viaptr
. It is well defined to modifyptr
itself.If ptr is declared as
Type * const ptr
,ptr
itself is aconst
, modifyingptr
is bad formed.I updated code.
But If we use
mdq
directly, then aelse
statement repeatingadd_weighted_dq_dq(...
will be necessary for no scaling case.I strongly recommand to use
deform_dq = &mdq;
, so that one unified call ofadd_weighted_dq_dq
is sufficient.Ah, yeah. I'm well aware of the semantics of
const *
, but I wasn't following the control flow correctly: I forgot about the case where theif
branch is skipped.All other things being equal, I think I'd prefer an
else
branch that callsadd_weighted_dq_dq(...
with different arguments. By convention, I think of const input parameters as sort of indication to not modify them, even though the semantics allow it. But I don't really feel too strongly one way or the other. So let's just leave it as-is.Ah! I should have looked at the changes first. Yeah, I think I prefer the else branch, like you've written it now. Thanks so much!
I brought this to the animation module meeting, and we agreed that we'd like to merge this once the code is in shape. I did another code review, with some change requests.
I did some testing with your new solution, and it works great! Awesome work!
I did find some extreme situations with shear that could still be improved, but this is already such a massive improvement (it addresses the vast majority of issues) that I think it makes sense to merge this latest solution. Further improvements can be done in a future PR if desired/needed.
Thank you so much for your work on this! Once you've addressed the change requests, I think this is ready to merge.
@ -66,1 +65,3 @@
add_weighted_dq_dq(dq_accum, deform_dq, weight);
if (deform_dq->scale_weight) {
/* FIX https://projects.blender.org/blender/blender/issues/32022 */
Just one last thing:
I would prefer
if (deform_dq->scale_weight)
to use an explicit comparison, likeif (deform_dq->scale_weight != 0.0)
.Because, for example, I'm not actually totally sure what the semantics of a
float
interpreted as a boolean is. I assume it just takes the the bits reinterpreted as an integer, and then 0 is equivalent to false. But I had to think about it. And it doesn't cover e.g. the case-0.0
which can happen with floats, but is equivalent to zero. So using an explicit comparison would, I think, make it both more clear and more correct.Out of curiosity, I looked up the defined behavior: https://en.cppreference.com/w/c/language/conversion
It turns out that using a
float
as a boolean is equivalent to first casting the float to anint
, and then using theint
. So, for example,0.5
converts to0
, which is false.This wasn't the behavior I expected at all, and also isn't the behavior my coworker here assumed when I asked him. Which I think is an indication that the semantics are non-obvious, and even if correct for the given situation probably shouldn't be used for the sake of code clarity.
Edit: further, it appears that at least clang doesn't follow that specified behavior. Which suggests that in practice it's compiler-specific.
This kind of usage (
if(float)
) is just a copy of existing code. seeI assume although
scale_weight
isfloat
, it should only be integers, so everything works as expected.I think it is better to leave it as it is now.
see also
mat4_to_dquat
anddquat_to_mat4
andnormalize_dq
in same file (math_rotation.c).I see through the defined behavior but:
So it appears there is no problem for
if(float)
statement, if the floating point value is non-zero, its boolean value will always betrue
as expected, even it could be converted toint
0.Ah, indeed, I misread the spec. I also didn't realize that was already being done in the code base(!).
I think that's fine, then. In the future we can migrate these cases to be more clear/explicit.
Thanks!
Thanks again for working on this!
Nathan Vegdahl referenced this pull request2023-06-06 12:41:06 +02:00
(Forgot to approve before merging. This week is not my week, ha ha.)
This seems to be ignoring crazyspace, which needs to produce a local transformation matrix, rather than simply transforming a single coordinate.
It also completely ignores the Armature constraint, which is supposed to produce the same result as the armature modifier, and also needs to produce a local transformation matrix.
I added a follow up PR #111759 that extends this to constraints and crazyspace (computing the full scale matrix when necessary).
Just wanted to say a big "THANK YOU", was waiting for that to be fixed for years. @angavrilov Great work! (hope i don't spam/don't pollute the thread with this comment... if this is perceived as is, feel free to remove it)
Eh, I just extended the fix to crazyspace (sculpting) and constraints, the main fix is by @himisa.
Oh ok! Thank you @himisa then!
I even tried to solve it myself, but did not succeed, probably lacking maths knowledge. You made my day.
This is even better than the Maya implementation, that uses an external global scale value to handle scale over dual quats.