import pose for prebended figures (aka daz orientation)

Issue #1445 resolved
Alessandro Padovani created an issue

daz studio 4.21.05, blender 3.4.1, diffeomorphic 1.7.0.1464

It seems import pose does something strange, that is, it makes some sort of cross-axis conversion that to my understanding doesn't make sense in euler based systems. The pose should just load as is, storing the pose values in the appropriate axis.

The issue only arises when loading a pose in a rig with a different rest pose than the original. This includes any daz custom figure imported as dbz, apart the default G8.

Below an example. To better show the issue we use a "prebended" Victoria 8 imported as dbz, then a pose that "unbends" the figure to the default daz rest pose. Files included prebended-v8.duf unbend.duf.

steps:

  1. import prebended-v8.duf as dbz and merge rigs
  2. import the pose unbend.duf

Now we see for example that the left shin rotation is messed up, it is -65 bend in daz so it should be -65 x in blender, but it's not. It's the same for the other bones all the values are messed up compared to the daz pose.

# import pose conversion
daz left shin rotation = -65 bend
blender left shin rotation = -64.6 x, -8.95 y, 8.91 z

Comments (37)

  1. Thomas Larsson repo owner

    No, I don’t think it works that way. To determine the pose in Blender, the plugin uses the rest poses in both Blender and DS. The rest pose in DS consists of the center point (pivot) and the orientation, but translations and rotations are not included. So roughly what you set in the Shaping tab. But the dbz file bakes the full pose, including what you change in the Posing tab. Hence the Blender rest pose differs from the DS rest pose in this case, and poses will not be imported correctly, although it might not be obvious how they differ. But it was a long time since I wrote this code and I may misremember details.

    That poses are baked is sometimes a problem in practice, e.g. for ladies wearing high heels. Then foot poses can be off because the rest poses differ. In DS she rests on her soles and in Blender on her toes.

  2. Alessandro Padovani reporter

    note. very important. IMPORT POSE ON PREBENDED FIGURES.

    For prebended figures, it would be extremely useful if we could store the unmorphed pose with the figure so that we can load daz poses even with a prebended dbz. That is:

    1. The unmorphed pose is available when we load as unmorphed, that pose could be stored with the figure for example in the object properties. We could have a option in the import panel.

    # store unmorphed pose
    object properties = unmorphed pose
    

    2. Now when we load a daz pose we can use the unmorphed pose as reference. This way the daz pose will work on prebended figures. We could have a option in the import pose panel.

    # use unmorphed pose
    figure pose = daz pose - unmorphed pose
    

    Please note that if the unmorphed pose is the rest pose then it will be zero, so the equation above still works. That is, we could always store and use the unmorphed pose, even if it is not necessary for the rest pose.

    @Thomas Larsson please let me know what you think. If you're not interested I'll close as "wontfix".

  3. Alessandro Padovani reporter

    @Thomas, to reply your comment above, as we see in #1418 the bone orientation in rest pose is not relevant when we load a pose, only the pivot matters.

    The example I provided is simple proof. If we bend the shin -65 in daz studio it has to be -65 x in blender. You already store the rest pose in the blender conversion so you don’t have to convert again when you import a pose. If you make the pose by hand in blender by using the values in the unbend.duf pose, you will see that you get the daz rest pose as expected. While if you use the import pose conversion it doesn’t work.

    Please take your time to verify, this is quite important.

    edit. note. PROOF. Another way to explain this. If you apply a pose then its negative the result must be zero by definition. So a daz pose with bend = 65 and another with bend = -65 must get the rest pose if both applied. If not then the conversion is wrong that’s what happens here.

    steps:

    1. Import prebended-v8.duf as dbz and merge rigs.
    2. Import the pose unbend.duf, that’s the negative of the prebended pose. You will not get the daz rest pose.

    comparison steps:

    1. Import prebended-v8.duf as dbz and merge rigs.
    2. Make the pose by hand by using the values in the unbend pose as is, without any conversion. You will get the daz rest pose.

  4. Alessandro Padovani reporter

    note. Please note that the example above is a “extreme“ case to better show the issue. But any daz custom figure is affected, since in a custom figure the rest pose is different. So for a custom figure imported as dbz the pose loaded in daz will be different from the pose loaded in blender, depending on how much the rest pose is different from the default genesis.

    If the custom figure has a rest pose very similar to the default genesis then the issue is not noticeable, this is the common case.

  5. Alessandro Padovani reporter

    If it is not hard to do, you could make a “use daz values“ option for import pose where the pose values are just copied in the relative axis, without further transformations. Then I can help with testing if this works fine.

    And thank you for your time thinking about this. I hope it will be an improvement unless I miss something.

  6. Thomas Larsson repo owner

    The plugin now subtracts baked rotations when poses are loaded. This definitely improves the situation, e.g. for the base poses. But as you noticed, there is still a difference compared to daz. The plugin doesn’t use the daz local rotations directly, but tries to match the pose in world space, and this creates rotations around all three axes. The formula for a pure rotation is (translation and scale complicate things)

    D = DAZ rest matrix
    B = Blender rest matrix
    R = DAZ local rotation matrix
    L = Blender local rotation matrix
    
    L = B^-1 * D * R * D^-1 * B
    

    I will think about using the daz rotations directly. It is not so easy because we still need to permute and maybe flip axes, since in Blender the Y axis always points along the bone.

  7. Alessandro Padovani reporter

    Well to match the pose in world space would be an excellent thing to do really. But I don’t think you’re doing the right thing with matrices since there’s the difference I noted above. I am bad with math especially 3D, but I can do it with constraints may be this can help you to figure out how to deal with the math.

    To match the pose in world space we can use a copy rotation, while copy location is only used for the hip bone. If the rest pose is the same this should also produce the same rotation values as daz.

    Below there’s a pseudo code and a partial implementation where I’m copying a pose from a G8F armature to a prebended Victoria 8.

    # match the pose in world space
    for all bones
        copy rotation in world space
    for the hip bone
        copy location in world space
    apply the constraints
    

    note. COPY ABSOLUTE POSE TOOL. It may also be very useful to have this “copy pose“ as a separate tool. Since blender provides a copy pose that only works between armatures if the rest pose is the same, or a copy global transform that only works for one bone. So a tool to copy the global transform of bones between armatures would be great, to copy the same pose among different prebended (dbz) armatures.

    Let me know what you think.

    https://docs.blender.org/manual/en/latest/animation/armatures/posing/editing/copy_paste.html

    https://wiki.blender.org/wiki/Reference/Release_Notes/3.1/Add-ons#Copy_Global_Transform

  8. Alessandro Padovani reporter

    note. SUPER DUPER IMPORTANT.

    As for commit eb4dd0c, with the new way of importing poses now the bone orientation in edit mode does matter. So this is a problem when we use "connect bones". I suspect in the previous version you used the bone child head to compute the orientation so it didn't matter if we changed the tails in edit mode.

    This would be ideal to keep. See #1418.

  9. Maliketh Blade

    I was just about to ask the same question. My pose does this after import. as i read just manually tweak it?

  10. Alessandro Padovani reporter

    Please don’t use the new commits until Thomas figures out a complete working solution. This is experimental and there may be bugs.

    @Thomas Until a final solution, may be it is better to use “experimental options” for the new pose system, so the old code is still available for production.

  11. Alessandro Padovani reporter

    update.

    Commit e11cae3 is excellent, just works perfectly in any condition.

    The new options “subtract rest pose” + “daz orientation“ reconstruct perfectly the rest pose for prebended figures. And, without the new options, I can edit the bone tails in edit mode and import a pose perfectly, so we can use connect bones.

    @Thomas please let me know if you can implement the “copy global pose“ tool as suggested above. That would be useful to copy poses among figures with same armature but different rest pose.

  12. Thomas Larsson repo owner

    Well, the previous commit had flaws, some of which have been addressed, but some remain for tomorrow. E.g. if you import Base pose kneeling B to standard G8F, one lCollar component is imported with the wrong sign, which makes the left hand penetrate the right arm. The old method works better here.

    In the latest version the option has been changed to a global option instead, in order to affect poses in scene files (if you import them without dbz). But even if you enable Daz Orientation, the old method is still used for old figures and for rigify, where the new method doesn’t work for some reason. It does work with mhx, though.

  13. Thomas Larsson repo owner

    To copy poses in world space is straightforward, but if you do it strictly there are problems with twisting if the armatures have different rest poses. The BVH retargeter therefore adds a T-pose at frame 0, to calibrate the difference in rest pose, cf. https://diffeomorphic.blogspot.com/p/bvh-how-it-works.html. That said, if the difference in rest pose is small this effect can probably be ignored.

    The Convert Poses option essentially copies poses between different genesis generations. Well, between G3 and G8 anyway, since the bone hierarchies should be the same (bend and twist bones).

  14. Alessandro Padovani reporter

    Commit e2b32e0.

    There’s something very odd I can’t figure out, but I can show you so may be you can understand what’s happening and fix it.

    steps:

    1. turn off “daz orientation“, import Victoria 8 as dbz and import the kneeling-b pose
    2. turn on “daz orientation“, import Victoria 8 as dbz and import the kneeling-b pose

    Now we see that the two poses align perfectly, apart for lShldrBend that’s the only different bone. But, if we look at the transformation values they are the same, the rotation order also is the same. So I can only assume the rest pose is different in some way but can’t understand how.

    p.s. The correct pose same as daz studio is with “daz orientation“ off.

  15. Alessandro Padovani reporter

    update. tip. I see that, if I change the rotation order multiple times for the shoulder bone, including quaternions, then when I set it back to YXZ Euler the final position is different. This means that, if for some reason the code is changing multiple times the rotation order of the bones, or it is converting to quaternions, then it may affect the final position.

    One combination that changes the final position is: yxz > quaternion > zxy > yxz

  16. Thomas Larsson repo owner

    I didn’t find a general solution, so I cheated and added the left collar as a special case. Not elegant but it works for the kneeling pose, except that the right toes are slightly off compared to the dbz pose.

  17. Alessandro Padovani reporter

    Commit a3a4441 seems to work fine.

    I’m perplexed that a cheat is needed, the conversion should be possible. We have 6 possible rotation orders in the duf file that correspond to the 6 possible rotation orders in blender. Then the rotation values have to be stored as is. Plus there’s the conversion to quaternion if we use it.

    Will look if I can figure out a conversion table and let you know.

  18. Thomas Larsson repo owner

    It’s more complex than that. Apart from the six Euler orders, we also have to interchange axes to make Y point along the bone. And it’s +Y that points along the bone, not -Y. In addition we want X to be the main bending axis, because both MHX and Rigify demand it. So the mapping between DS and Blender axes is a mess, and it took months for Engetu and myself to figure it out. If we did.

  19. Alessandro Padovani reporter

    Yes I see in the daz joint editor that the daz bones can roll in all three axis XYZ depending on the bone, while the blender bones always roll in Y as you noted. This makes the conversion dependent on the daz roll bone. The main bending axis in daz studio is variable too but it is always defined by the label “Bend“.

    To assign the rotation values, it is then necessary to keep a “conversion map” for each bone with the daz axis for YXZ in blender.

    Let me know if this helps or is all something that you already considered.

    # daz to blender bone axis conversion
    blender y = daz roll axis
    blender x = daz axis where label = "Bend"
    blender z = remaining daz axis
    

  20. Thomas Larsson repo owner

    The bone map was worked out long ago and I don’t want to touch it anymore. If you want to see how the bones are oriented in DS, turn on the global setting Unflipped Bones. Also disable Z Up to use the same global coordinate system as DS. I used these settings in the beginning to get the basic stuff right without having to worry about conversion to Blender coordinates.

    You may want to look at http://diffeomorphic.blogspot.com/2020/08/daz-studio-bones.html.

  21. Alessandro Padovani reporter

    As for the shoes example the jcms will not work fine that way, as well as poses and animations unless we "subtract rest pose". For everything to work fine we need to export the dbz in rest pose. Then we can import the feet pose for the shoes if we want to.

    As I see it the use for prebended figures is not to make the shoes work, that does not anyway, but it is to simplify the figure so that we can bake the main deformations in the prebend and avoid importing and trasferring tons of jcms. This will not be nice as full jcms but works fine enough and it is much more blender friendly.

    https://diffeomorphic.blogspot.com/2023/01/

    As for "not touching the old code" I agree it is too risky, the new system has to be a experimental option until it works fine. Actually to use a "heuristic" for lCollar means there's a design flaw.

    I'll look at it and let you know if I find something.

  22. Alessandro Padovani reporter

    update. bug. regression.

    Commit 913c959 doesn’t work with quaternions. While commit a3a4441 was not perfect but much better with quaternions, it also was slightly better with eulers for the kneeling-b pose. From the commit comment I can’t understand what’s changed but it’s worse than before.

    steps:

    1. turn on “daz orientation“ and “quaternions” in global settings
    2. import the test scene prebended-v8.duf as dbz and merge rigs
    3. load the pose kneeling-b with “subtract rest pose“

  23. Alessandro Padovani reporter

    note. important.

    The “copy absolute pose“ tool described above could also be useful for comparisons. That is, if we have “copy absolute pose“ we can copy any pose to a prebended rig. The tool as described above with constraints seems to work very good in my tests.

    About your comment for flipping issues, this doesn’t happen for a single pose, or I’m unable to reproduce the issue. Indeed it may happen in animation when interpolating among poses, but using quaternions should fix it, apart extreme cases if the two poses to interpolate are completely different.

  24. Thomas Larsson repo owner

    I think I got it. We cannot just subtract the baked rotation; Euler angles don’t work that way. What we have to do is to multiply the rotation matrix with the inverse of the baked rotation matrix. When we do that posing works almost flawlessly. I used one of the base poses as rest pose and could load the others.

    For quaternion bones we cannot just interchange Euler angles, so then we have to resort to the old method using matrices. Then the pose is not perfect anymore, but if only the shoulders and thighs are quaternion the result is pretty good anyway.

  25. Alessandro Padovani reporter

    As for commit e829d1b.

    1. question. What do you mean you got it. Does it mean you don’t use the heuristic anymore but invert the matrix instead ?

    2. bug. copy absolute pose.

    It seems copy absolute pose also copies the bone location, that is not good because different figures have different proportions. As explained above we have to only copy the rotations, plus the location only for the hip bone. Below an example where I copied kneeling-b from G8F to Victoria 8 we see the feet are misplaced.

    note. When copying and applying rotations it is probably better to start from the root and follow the bone chains recursively.

    note. feature request. The copy pose tool actually works fine with the simple rig. It could be useful for it to work with mhx and rigify too. Otherwise to place a warning in the tooltip that it only works for the daz and simple rigs.

    3. note. important. about “subtract rest pose” and body morphs.

    In the test scene prebended-v8.duf I used body morphs to bend the fingers. Now while the mesh and bones are baked fine in the dbz, the “subtract rest pose“ tool can’t figure out what the rest pose for the fingers is and assumes it is the bended fingers. Thus if we load a G8F rest pose on prebended-v8 the fingers are bended because of the body morph.

    steps:

    1. import prebended-v8.duf as dbz and merge rigs
    2. import the G8F rest pose, we see that the fingers are bended

    One way to fix this is to bake the body morph in daz studio before exporting the prebended figure. That is, if we want to work with a prebended figure then be sure to bake the body morphs before exporting, or don’t use body morphs to prebend the figure. To bake the body morphs in daz studio the tool is edit > figure > bake to transforms.

    note. This applies both to the new “daz orientation“ and the old standard orientation.

    note. This doesn’t apply to “copy absolute pose“, since the tool is not affected by rest poses.

  26. Alessandro Padovani reporter

    update. about “subtract rest pose” and body morphs.

    If we import prebended-v8.duf as unmorphed, then the fingers are straight. I don’t now if this can be used to fix point 3 above. Otherwise we have to bake in daz studio.

    Please let me know.

  27. Thomas Larsson repo owner

    By “getting it” I meant the insight that Euler angles cannot be added, you must multiply rotation matrices instead. Except if all rotations are around the same axis.

  28. Thomas Larsson repo owner

    Bone locations are no longer copied, except for bones without parent. This should be modified to work with more advanced rigs where the hip and ik goals are parented to a master bone. But not today. Other improvements: Locked channels are cleared (otherwise they usually become something very small due to rounding errors). And the tools sets keyframes if auto keying is enabled.

    Copying poses between different bone hierarchies, like mhx and rigify, would be far more ambitious, and I don’t want to go down that lane, at least not now.

  29. Alessandro Padovani reporter

    Commit 4422cdc works great. Thank you Thomas for the fast fix and the nice improvements.

    Will leave this open for now since I want to do more tests and see if I can help more with “daz orientation“.

  30. Log in to comment