better triax conversion

Issue #1731 resolved
Alessandro Padovani created an issue

1.7.2.1794

The actual conversion from triax to general weight is unfortunately quite rude, both in daz studio and inside the addon. Once we import a G1 G2 figure and try to pose it we get spikes and artifacts around.

We can definitely improve the conversion by smoothing the weightmaps, not too much to avoid “jelly“ effects, the parameters below seem optimal to me. We may include an option in global settings to smooth triax, possibly with a smooth level default to 4.

steps:

  1. enter weight paint and smooth the pose bones, factor = 0.5, iterations = triax smooth in global settings

Below a comparison for G2F before and after the smooth. We see the deformations are effectively improved.

bug. triax warning. Actually the addon doesn’t warn for triax weight when we load a G2 figure. Oddly it warns for triax weight if I convert to general weight in daz studio. Some daz figures include both triax and general weight, that is “blended weight” that would use triax and general together, in this case we can approximate with general weight alone, essentially we lose the bulges from triax but this is minor.

Note that scale maps are always ignored with no warning since blender doesn’t support separate weightmaps for scale.

# weight conversion
if there’s general weight + triax maps
    warn for blended weight
    use general weight and ignore triax
else if there's general weight alone (G3 G8 G9)
    no warnings
    use general weight
else if there's triax alone (G1 G2)
    warn for triax
    do triax conversion and smoothing
else if there's no weight maps (old Poser content V3 V4)
    warn for no weight maps
    do automatic weight in blender

Comments (33)

  1. Alessandro Padovani reporter

    request. triax maps ?

    Thomas, if we may have an option to import the triax maps, perhaps in the debug section. I’d like to do some tests to see if I can get some better conversion out of them. Otherwise I have no way to extract triax maps from daz figures.

  2. Alessandro Padovani reporter

    Commit f23e9d4.

    Now G2 warns for triax weights, thank you for the fix.

    The global option for triax works wonderful, thank you. I see you only import xyz maps, for triax there’s also bulge maps that are important for some bones. If it is not a hassle it would be nice to have them imported to experiment with. Let me know.

    I see you didn’t implement the triax smoothing. I understand we can do it by hand, but when we import a full G1 G2 figure with hair outfit and accessories, smoothing by hand every single mesh can be time consuming. Having a global option to do so would be handy. Let me know.

  3. Thomas Larsson repo owner

    Triax smoothing and bulge groups are added in the last commit. You get scale groups too even though you didn’t ask for it. THe local and bulge groups are not smoothed since the don’t have associated bones.

  4. Alessandro Padovani reporter

    Commit 26cac7b.

    The triax smooth is wonderful thank you for the fix. There’s no use for scale maps since blender doesn’t support separate weightmaps to scale bones, but for completeness they may be interesting to have.

    p.s. Will leave this open for a while to see if I can come out with something, also if others want to contribute now that we have triax maps for testing.

    possible bug. global settings. I noticed that, differently from before, when we change a global setting we have to restart blender for the new setting to apply. This may not be a bug but something to be aware of. Also a minor nuisance if we have to change some settings inside the work session.

  5. Thomas Larsson repo owner

    You shouldn’t have to restart Blender for the new settings to take place. However, I had misspelled a few settings which meant that the settings dialog didn’t update the real settings when it was closed. Also, if there is a new setting, like Smooth Triax Weights today, it seems necessary to restart Blender.

    Another thing that has happened to me is that the mouse hovered over a checkbox when I hit return. Then Blender changed the checkbox before saving the settings. Very irritating.

  6. Alessandro Padovani reporter

    update. exploring triax.

    I will use this discussion to explore triax, with the goal to eventually provide some support for triax in blender. This would allow to use G1 G2 figures with deformations similar to daz studio. Also, now that Thomas made triax maps available, anyone can experiment and contribute.

    1. dual quaternion. The first thing we notice is that triax is based on dual quaternion. While the triax maps provide independed axes and displacement, the base layer is dual quaternion. So it is good to keep "preserve volume" enabled when we import triax in blender.

    Below there's a comparison where I only use the triax map for bending, it's the same in blender and daz.

    2. bulge maps. These are necessary to sculpt deformations, for example for knees and elbows. The daz panel provides two parameters to define the bulge intensity, "positive" and "negative" are for positive and negative values of the axis euler rotation. Note that left and right maps are provided for each axis.

    In my tests a 0.002 factor provides a good match for a 90 degree rotation that I normalize with.

    # triax bulge, same for left right maps, same for x y z axes
    if rotation x > 0
        displacement = x bulge left * x bulge positive left * 0.002 * abs(rotation x / 90)
    if rotation x < 0
        displacement = x bulge left * x bulge negative left * 0.002 * abs(rotation x / 90)
    

    note. bulge to jcm. Note that the displacement modifier could be baked to a shapekey and converted to a jcm with a driver, following the equations above. This way we could have triax bulges in blender.

    Below an example where I used the bulge map for the thigh in blender.

    Below another example where I used the bulge map for the forearm, always following the equations above. We get a nice triax elbow in blender.

    3. independent axes. This is the most interesting part, and probably harder to get in blender. Will update on this.

  7. Alessandro Padovani reporter

    update. triax bulges implementation.

    After some testing I believe the actual conversion with triax smoothed weights is not bad for practical use. What we really miss is to import the triax bulges for deformations, to avoid the “jelly joints“ look. This is equivalent to jcms for general weight, we could have a “import triax bulges“ tool in the morphs panel, eventually also added to easy import as default for G1 G2.

    The implementation seems not hard. Basically we turn the bulge maps into shapekeys via displacement modifiers, then add drivers following the equations above. I did a test scene triax.blend where I implemented the bulges for the G2F left elbows and knees, that can be used as reference. Note that bulges can be implemented either with displacement or jcms, in the test scene I included both versions, but I believe jcms is the ideal solution since having lots of displacements in the figure is not common practice.

    To generate shapekeys from displacement I used a -0.02 factor, since this gives a nice shapekey same as if it was sculpted by the artist. I believe it is important to have a nice visual feedback for the shapekey.

    # triax bulge, same for left right maps, same for x y z axes
    if rotation x > 0
        displacement = x bulge left * x bulge positive left * 0.002 * abs(rotation x / 90)
    if rotation x < 0
        displacement = x bulge left * x bulge negative left * 0.002 * abs(rotation x / 90)
    
    # driver conversion for displacement, 1.571 is for radians
    x_bulge_positive_left * 0.002/1.571 * X if X > 0
    else x_bulge_negative_left * -0.002/1.571 * X if X < 0
    else 0
    
    # driver conversion for shapekeys
    # we bake with a -0.02 factor for a nice shapekey, so 0.002/-0.02 = -0.1
    x_bulge_positive_left * -0.1/1.571 * X if X > 0
    else x_bulge_negative_left * 0.1/1.571 * X if X < 0
    else 0
    

    Below there’s the test scene with two G2F figures featuring displacement and jcm bulges. @Thomas Larsson let me know what you think if you can implement this, also of course if something is not clear. This would be a nice step forward for triax.

  8. Alessandro Padovani reporter

    note. shapekey limits.

    For jcms I baked the bulge maps with a -2 cm offset that gives a nice shape sculpted on the base mesh. Now we don’t really know how much the bulge expression will push the bulge, so in the test scene I used +- 2 limits for the shapekeys that gives a max 4 cm offset from the base mesh. May be it’s better to use +- 5 limits for a max 10 cm offset that should be safe for any corrective bulge.

    Note that the same bulge map can be used both with positive and negative offset by the bulge expression, depending on the positive or negative euler rotation, this is why we need both positive and negative limits.

    Note that the limits don’t influence the expression itself, they’re just a “clamp“ for it.

  9. Thomas Larsson repo owner

    Implemented in last commit. When the G2 character is imported, you have to press the Morphs > Create Bulges button to convert the vertex groups to shapekeys. Once we are confident that the bulges are correct, we might remove the button and create the bulge shapekeys directly when the character is imported.

    I also removed the warning about triax weights.

  10. Alessandro Padovani reporter

    Commit 46ae3c3.

    That’s AMAZING thank you for this. Below a couple notes, but I believe we’re essentially there.

    1. bug. shapekeys baking. It looks like you didn’t bake the displacement right, probaly you used a 1cm factor instead of 2cm. This way the bulges are half the height. If you pin the shapekeys in the test scene you see that the actual implementation has lower bulges.

    2. triax warning. While this is certainly a good improvement, we’re far from perfect in importing triax. I mean general weight is imported same as daz studio, while triax is a “not bad“ approximation. So a warning may make sense anyway, as for example “warning: triax approximation used“.

    3. bulge conversion option. This is equivalent to jcms for general weight. So we may want to select the bulges to convert, same as we select the jcms to convert. This is useful to customize or optimize the figure, plus we may not want bulges for prebended figures imported as dbz.

    Let me know, and thank you again.

  11. Thomas Larsson repo owner

    The problem was that I missed to set the mid_level of the displace modifier, so it was set to the default 0.5. The other changes have also been made. The vertex groups are removed even if the bone is not selected, so you have only one chance to create the bulge shapekeys. I’m not sure that this is what we want, but we probably don’t want that a lot of unused vertex groups are left behind either.

  12. Alessandro Padovani reporter

    Thank you so much, I’m evaluating the new commit and will let you know. I can confirm the shapekey bug is fixed.

  13. Alessandro Padovani reporter

    1.7.2.1825

    update. triax twist implementation.

    If we look at G2F in daz studio we can see that arms and legs twist nicely, sort of the twist bones in G8F, this is due to the triax twist maps. We can achieve something similar by adding twist bones to G2F and using the triax twist maps.

    1. triax to general. The first step is to convert triax to general weight. Here we don't need twist because we deal with it later for specific bones. Also because the triax twist maps are not straightforward to use and require special treatement for each bone, as we'll see below.

    Here we only use bend and side maps by average, then we smooth. Of course this is a simplification of triax.

    # convert triax to general weight
    general weight = normalize(average(triax.bend,triax.side))
    smooth
    

    note. The bend and side for triax can be any axis depending on the bone. So we have to check the daz labels. Same for twist it can be any axis.

    note. The actual implementation is not bad, but it leaves "artifacts" around and I'm not sure if this is because it also tries to integrate twist maps, that's not possible in the general case.

    2. twist bones. Once we have the general weight in place we add the twist bones. Not all bones need a separate twist, we only add twist to arms and legs same as G8F. Again this is a simplification of triax, same as it was a simplification averaging bend and side.

    In the procedure below, note that the twist bone takes the general weight map, while the original bone takes the twist map. This is sort of reversed, but we need this because the pose to copy from is in the original bone.

    To convert the triax twist map to a general weight twist map we have to limit the twist to the range of the bend-side map, so we multiply. Below an example where we see that the twist map for the arm extends to the forearm, this can't work in general weight.

    # add twist to arms and forearms, same for l/r
    duplicate bone lShldr to lShldr.TWIST
    copy rotation XZ from lShldr to lShldr.TWIST
    lShldr.TWIST map = general weight
    lShldr map = normalize(multiply(triax.twist,general weight))
    
    duplicate bone lForeArm to lForeArm.TWIST
    copy rotation XZ from lForeArm to lForeArm.TWIST
    lForeArm.TWIST map = general weight
    lForeArm map = normalize(multiply(triax.twist,general weight))
    
    # add twist to legs, same for l/r
    duplicate bone lThigh to lThigh.TWIST
    copy rotation XZ from lThigh to lThigh.TWIST
    lThigh.TWIST map = general weight
    lThigh map = normalize(multiply(triax.twist,general weight))
    

    3. tweak for forearm twist. For the forearm twist map I used the twist map of the hand, this is because the twist map for the forearm doesn't extend to the wrist so we can't use it for general weight. Luckily the triax for G1 G2 is similar so we can use this same tweak for both.

    4. final result. Below the final result, test scene included triax-twist.blend. I added twist to the left side and we can see the difference with the right side that doesn't include twist bones. The effect is similar to the triax twist.

    Of course let me know if something is not clear.

  14. Alessandro Padovani reporter

    note. forearm twist and outfits.

    I had a doubt about the forearm tweak for the twist bone, since we take it from the hand, that it may have issues with outfits. But, looking at some G2 outfits with long sleeves, it seems the hand twist map is always included for the sleeve, probably transferred from the base figure.

    So the forearm tweak seems safe with outfits too.

  15. Thomas Larsson repo owner

    I have implemented the first two steps above, but it probably doesn’t work because I don’t understand how the vertex mix modifier works. Quaternions must be disabled in the global settings for now.

  16. Alessandro Padovani reporter

    Commit c10c8b4.

    Thank you for looking at this. I had a look at your code and I believe to understand what’s wrong, beware that I know very little of python and the blender api, so please verify. The documentation for the mix modifier can be found in the blender manual as usual. But I believe you confuse the modifier name with the map name, that is, the modifier affects “vertex group A“ as final result.

    https://docs.blender.org/manual/en/latest/modeling/modifiers/modify/weight_mix.html

    bug. general weight. I see you convert to general weight the twist bones. Here there are three errors. First this is to be done for all bones instead of the actual conversion, not only for twist, with smooth as a final pass. Second we have to assign the bend map to the bone first, that is, we have to rename the map from “bone:x” to “bone” to bind then use it as “vertex group A“, and “bone:z“ as “vertex group B“. Third we don’t know if bend is X and side is Z, in daz it can be any axis, we have to look at the daz labels or at the conversion table if there’s any.

    bug. twist weight. Then when you convert twist there’s the same error. We don’t know if twist is Y.

    bug. skinbinding. The weight mix must be done before the armature in the modifier stack, not after.

    As for quaternion there shouldn’t be any trouble, apart we have to use the explicit euler order for copy rotation.

    Let me know.

  17. Alessandro Padovani reporter

    As an example I’ll do lShldr.

    steps for general weight, with smooth as final pass after all bones are done:

    1. rename the vertex group “llSldr:z“ to “lShldr“ since Z is the bend axis in daz, this binds the bone
    2. mix with “lShldr“ as “vertex group A“ and “lShldr:y“ as “vertex group B“ since Y is the side axis in daz

    steps for twist, after general weight is done:

    1. rename the vertex group lShldr to lShldr.twist, since the twist bone takes the general weight
    2. rename the vertex group “lShldr:x“ to “lShldr“, since X is the twist axis in daz, this binds the main bone to the daz twist map
    3. mix with “lShldr“ as “vertex group A“ and “lShldr.twist“ as “vertex group B“

    edit. errata corridge. I corrected the steps for twist.

    p.s. Of course I used modifiers because I can’t code python, there may be functions in the blender api to do the same.

  18. Thomas Larsson repo owner

    I made the changes but now it doesn’t work at all. This is strange because the vertex groups are present in weight paint mode. I made a commit so you can have a look.

  19. Alessandro Padovani reporter

    Commit 0add656.

    The weightmaps look good, apart that we have to use the hand twist triax map instead of forearm twist as in point 3 above, please fix this. You just forgot to set the bones as “deform“ that’s why the mesh doesn’t move.

    notes. important. I see you left the modifiers there in the last commit, I understand this is to let me see them. Of course you can apply the modifiers after mixing we don’t need them. Also we have to smooth after creating the general weights and before creating the twist weights, that you didn’t.

    We may remove the triax smooth option from the global settings since smooth for general weight must be done, triax conversion is not good without smooth.

  20. Thomas Larsson repo owner

    Things may be working now. I applied the vertex mix modifiers for general bones, but left them for twist bones for now. We can also remove the unused vertex groups (:z) once the modifiers have been applied.

  21. Alessandro Padovani reporter

    Commit 51604ea.

    Thank you for your work and patience so far. This is what I found.

    bug. forearm tweak. I see in the mix modifier that to get the forearm tweak you multiply the forearm twist map with the hand twist map. This is wrong, instead we need to multiply the forearm general weight map with the hand twist map.

    # forearm tweak, same for l/r
    apply the general weight modifiers, this includes shldr.twist forearm.twist thigh.twist
    copy forearm.twist to forearm, this copies the general weight
    mix forearm with hand:x
    

    bug. smooth. We can’t keep the mix modifiers, otherwise smooth doesn’t work because the mix comes in the way. It is important to apply all modifiers before smoothing. So smoothing comes as a last pass after all weights are computed and all mix modifiers are applied.

    # smooth triax
    apply all mix modifiers
    smooth all
    

    bug. G8. I get an error when I load g8f.

    Loading C:\Users\Alessandro\Documents\DAZ 3D\Studio\My Library\Scenes\g8f-base.duf
    Parsing data
    Preprocessing...
    Building objects...
    Ignore <Instance Tonemapper%20Options-1 L:Tonemapper Options 0 N: Tonemapper Options P: None R: None>
    Ignore <Instance Environment%20Options-1 L:Environment Options 0 N: Environment Options P: None R: None>
    Add triax twist bones: Genesis 8 Female
    Traceback (most recent call last):
    File "C:\Users\Alessandro\AppData\Roaming\Blender Foundation\Blender\3.6\scripts\addons\import_daz\error.py", line 223, in execute
    self.run(context)
    File "C:\Users\Alessandro\AppData\Roaming\Blender Foundation\Blender\3.6\scripts\addons\import_daz\main.py", line 286, in run
    self.loadDazFile(filepath, context)
    File "C:\Users\Alessandro\AppData\Roaming\Blender Foundation\Blender\3.6\scripts\addons\import_daz\main.py", line 180, in loadDazFile
    asset.postbuild(context, inst)
    File "C:\Users\Alessandro\AppData\Roaming\Blender Foundation\Blender\3.6\scripts\addons\import_daz\modifier.py", line 663, in postbuild
    eb = rig.data.edit_bones[bname]
    KeyError: 'bpy_prop_collection[key]: key "lShldr" not found'

    note. triax debug. If possible it would be useful to keep the triax debug option, otherwise there’s no way to do further experiments since the maps are lost when we load the figure. Ideally we need to always keep the original triax maps when the debug option is enabled.

    note. minor. wire viewport ? I see you set wireframe in the object viewport display properties. This is unexpected and not necessary, I guess it is a leftover from debugging.

  22. Thomas Larsson repo owner

    OK, everything should be fixed now. The new triax debug option does several things:

    1. Duplicate the local weights groups.
    2. Keep vertex group modifiers.
    3. No smoothing.

    The forearm groups now has two modifiers, like this. When debugging is off the modifiers are applied from top to bottom.

    I’m thinking about renaming the extra bones to .bend instead of .twist. After all, that’s what they do.

  23. Alessandro Padovani reporter

    Commit edfd478.

    This works almost fine.

    bug. quaternions. The twist bones are all quaternions, they must copy the rotation order from the original bone, this is especially important since they copy rotations. If quaternion is specified in the global settings then shoulders and thighs will be quaternions as usual, but not the twist bones.

    fix. ik rigs. Now that we have twist bones for G1 G2, we can add the automatic twist for the forearm, same as G3 G8. Below the steps for simple ik, then mhx and rigify should provide the feature too. Test scene included g2-simple-ik.blend.

    G1 G2 automatic forearm twist for simple ik:

    1. duplicate forearm to forearm.ik, where forearm.ik is non-deform
    2. assign the ik constraint to forearm.ik
    3. copy rotation from hand.ik to forearm with dumped track on y, as the picture below, note that we use the explicit rotation order of the target

    note. As for the “twist” suffix it is not because they twist, indeed they bend, but it is because they serve the twist purpose. Adding extra bones with “bend“ suffix would be strange.

    final notes. Once we fix the ik rigs the new triax is complete. It is not perfect by any means, the original daz triax is much better, but this is definitely an improved approximation from the original conversion and the daz one. We added a better general weight conversion with smoothing, plus bulges and twist.

  24. Thomas Larsson repo owner

    The bugs should be fixed now. First I didn’t look at your file and implemented forearm twisting differently, but you way is better. It was also much easier to implement, since the code already existed for G8. Now all genesis versions, including G9, have the same extra bones.

  25. Alessandro Padovani reporter

    Commit 32fcd6e works fine.

    I'm closing as resolved. Eventually we can improve further if we find better ways to convert bulges or triax weights in general. But this first step is not bad if we want to use G1 G2 in blender.

    Thank you Thomas for all your work on this.

  26. Log in to comment