FACS Units not working

Issue #389 closed
garden created an issue

Hi, the plugin does not prescribe the correct dependencies for FACS Units.

For example, the morph "Eye Look Side-Side", when activating the morph, the morphs "Eye Look Side-Side Left" and "Eye Look Side-Side Right" should be activated,
which in turn activate "Eye Look In Left", "Eye Look In Right", "Eye Look Out Left", "Eye Look Out Right". But none of them are activated because they are not written to the driver dependencies.

And there are a lot of such morphs.

If the plugin can't register them automatically, then I can spend time once and register all the dependency paths manually.

Let me write them as you say (a table or a text file or a blender file), and then you could make the plugin prescribe the paths of dependencies according to my notes.

Because each time manually prescribing paths to morphs is a very useless exercise.

These facial morphs are an important thing, they are just as necessary as JCMs.

Comments (87)

  1. Thomas Larsson repo owner

    OK, I understand. The plugin handles the case with properties that drive properties that drive shapekeys or bone rotations, but not bone rotations that drive properties. In this case we have the following dependencies:

    • facs_ctrl_EyeLookSide-Side drives facs_ctrl_EyeLookSide-SideLeft
    • facs_ctrl_EyeLookSide-SideLeft drives lEye?rotation/y
    • lEye?rotation/y drives facs_ctrl_EyeLookInLeft
    • facs_ctrl_EyeLookInLeft drives facs_bs_EyeLookInLeft_div2

    If lEye?rotation/y had been a property, things would have worked correctly, I think. But now it is a bone rotation. Will need some time to deal with this.

  2. engetudouiti

    I suppose to make it all work, you may separate one property as 2 property as same as daz do (though user can not see 2 proeprty directly in UI)

    that means “prop1” divide as “final value prop 1” (UI show the value) and “daz raw value prop1” (UI user controll value)

    So we can still change raw value of all prop (it has no driver, never be driven) , and we only change the raw prop value. at same time, the final value are driven, include self raw prop value. then user never touch it, but just see the driven “final value prop1” (driven by bone, or by other prop)

    it is almost same logic you divide bone as drv-bone and user controll bone. (though the circulation change, because, drv-bone transform + controll bone transform = final bone transform value.

    And blender not offer such transform property for bone transform, (it only show final value, so user can not controll it when they are driven, so we may still use drv-bone and controll bone. but need to change driver expresison to it work. (so you often have modified them)

    I do not requesit it serisouly, but if you plan it as long span, it may offer more flexible controller and driver like daz. I suppsoe.

    (but how to check ERC formula which saved 2 different way (save with controller or save with sub-component file) I have no idea without actually point out all one by one. (though add on seems already try to generate when we load all related morphs, as you said, it still cause issue with deep hieralchy ERC)

  3. garden reporter

    Well, we can just set all the drivers manually, i.e. the plugin will not look at the formula, it will know in advance what it needs to register in the driver if it loads a morph with a certain name.

  4. Thomas Larsson repo owner

    That I don’t like at all, but it may be an alternative in the short run. This solution will break as soon as the plugin encounters some unknown assets.

  5. Thomas Larsson repo owner

    As I wrote in issue #388, the morph loader has to be rewritten. Today it only works correctly for morphs that are either pure face rig poses or pure shapekeys. It needs to handle mixed cases too, both for FACS morphs and for the HD morph textures generated by Xin’s addon in #357, but currently the code that does that is a total mess. If no simple bugs appear soon, I will proclaim the current development version to be stable version 1.5.1, and start to work on the morph loader tomorrow.

  6. Xin

    Thomas, once you get into re-rewriting the loader, I would recommend you to look into what this addon does with drivers too: https://rbfdrivers.readthedocs.io/en/latest/user-guide/overview/

    Just read the first few pages to get the general idea and then skip to the FAQ: https://rbfdrivers.readthedocs.io/en/latest/user-guide/faq/.

    I got the idea for #393 from that addon (not the addon itself since I don’t have it, but the docs), since it claims it only uses Simple Expressions for what are quite complex driver expressions (that addon needs to use exponential functions and such). So it should be possible to do the same here with relatively simpler daz expressions, and I believe that using Simple Expressions would make your life easier in the long-term too. Why? because you are basically storing intermediate results in new properties instead of trying to calculate everything in one expression. So every step becomes easier to manage from a scripting perspective.

    I agree that this shouldn’t be rushed, you are right that this should only be done after a stable version is released, since it requires time and testing.

    After the release, have you considered using a git branch? once you finish this release, leave the release branch for bug fixes and all the new morph stuff could go in a new branch. This would also make your life easier, as it would prevent people from creating tons of new issues for the unstable version.

  7. Thomas Larsson repo owner

    Using intermediate properties would certainly simplify things, but will it work? I tried something like that long ago, and there were serious update problems. E.g. is DS EyeBlink drives the EyeBlinkLeft and EyeBlinkRight properties, which in turn drive the eyelid bones. In Blender, changing EyeBlink did change the two other properties, but the bones only moved at the next frame, because Blender evaluated the drivers in the wrong order.

    It is possible that the new depsgraph in Blender 2.80 solved that; the mechanism for letting EyeBlink drive the bones directly was already in place then so I didn’t test. Letting every property that drives a shapekey indirectly also let it drive it directly would be very unattractive for the FACS morphs, because some drivers would become unwieldy, especially for the facs_cbs morphs. It won’t work in Blender 2.79 though, but I think it may be time to drop support for that anyway, since it adds quite a bit of complication to the code. Stable 1.5.1 will still be around if somebody still uses B2.79.

    Although I notice that the RBF drivers are limited to posebone transform channels. Is there a reason for that other than it is the most common case?

  8. Thomas Larsson repo owner

    Even if some FACS morphs don’t work correctly, I think that the tools that load facial mocap may still work. The mocap files only use a limited set of the FACS morphs, and typically the most basic ones that drive the shapekeys directly. So all is not lost.

  9. Xin

    Using properties to drive other properties and then in turn use those to drive bones' transforms is what is done in the example at #393 . The RBF drivers do something similar I believe, according to the FAQ: https://rbfdrivers.readthedocs.io/en/latest/user-guide/faq/ . This is all executed by Blender internally, in C++, so you would also get performance gains in CPUs with multiple cores.

    I don’t think I used Blender’s drivers before 2.80, so I can’t tell if that was an issue before. Could it be that it was an issue with Python evaluation only? I can imagine how complex it would be to keep track of all inputs and dependencies in an arbitrary Python function that uses other objects and such. But Blender’s Simple Expressions are quite straight forward and explicit: https://docs.blender.org/manual/en/latest/animation/drivers/drivers_panel.html#simple-expressions

    I agree that dropping support for older Blender versions is needed, it adds a lot of work for increasingly fewer gains.

  10. Thomas Larsson repo owner

    One thing to keep in mind is that the driving expression must not be longer than 256 characters. This is a serious limitation. Before the evalMorphs functions were introduced, I used a shoehorn to squeeze the info from each slider down to six characters (sign + 3 digits + * + variable name). This meant that at most 53 morphs could influence each face bone.

  11. Xin

    Yes, that’s why I think Simple Expressions and array properties for intermediate results will make your life much easier.

    The Sum Values type of driver, which is Simple Expression, has no apparent limit in the number of inputs. Those inputs can themselves be driven floats from an array property, which were defined as Simple Expressions too.

    For long multiplications you need the Scripted type of driver, but it’s easy to imagine a chained multiplier that is still a Simple Expression: Just take the first X inputs (which themselves are Simple Expressions) and multiply them together, then store the result in a driven property. Then use that property as the first input in a second Simple Expression multiplier that multiplies the rest of the inputs. You can implement a class that takes care of setting up all this by using an array property, and then offers a clean interface to the rest of the code. I don’t think you would run into dependency issues if you keep working with non-Python Simple driver Expressions, where all the inputs are clear and explicit to Blender.

  12. Thomas Larsson repo owner

    A sum driver can sum an infinite number of properties, but that is not what we want. We want a sum of terms of the type constant factor * property value, and it is unusual that the factor happens to be unity. You seem to suggest to create lots of intermediate properties (perhaps an array) driven by simple expressions of the type factor*value, and then use a sum driver to get the final result. Well, that is essentially what the evalMorph functions do. I don’t understand how this would simplify things.

    And there is another problem. In DS EyeBlink drives EyeBlinkLeft which drives the left eyelid bones. That can be mimicked in Blender by property drives property drives bone rotation. But in DS EyeBlinkLeft can also be changed independently, which is impossible in Blender if it is driven. This is reminiscent of the the situation with bones driving bones. The Make All Bones Posable button fixes that by adding an extra bone that is parented to the driven bone, but can also be posed freely. Building on that analogy, we need to make a new property EyeBlinkLeftDrv which is driven by EyeBlink, and then parent the EyeBlinkLeft property to it. But of course this does not make sense, since properties don’t have parent-child relationships. So instead both the EyeBlink and EyeBlinkLeft properties drive the same bones.

  13. engetudouiti

    For EyeBlinkLeft, if I make all prop as Prop(raw) and Prop(final),

    I make EyeBlinkLeft(raw) and EyeBlinkLeft(fin) , not EyeBlinlLeft(drv).

    the reason is so we can set driver function for each(fin) as same manner as ERC formula of 2nd stage(multiple)

    All prop(raw) (user input value) and porp(fin) (final value of the prop) relation should be

    <(prop(raw) + prop2(fin)*step value + prop3(fin)*step value + …) (1st stage delta add) > * <propA(fin) * propB(fin) * propC(fin)….. (2nd stage multiple)> = prop(fin)

    if there is no driver prop which drive prop(fin) , then prop(fin) = prop(raw). so all prop(fin) should have driver expression. why it work better,, you can add 2nd stage multiple as you need.

    For bone you represent it with bone(raw) and bone(drv) , then they are auto added as final bone(fin) transform value.(we simply see it as how bone(raw) moved from rest pose positoin of bone(drv)

    bone(fin) = bone(raw) + bone(drv) so, if bone(fin) drive other prop, you need to exchange it as (bone)(raw) + bone(drv) .

    Then for prop, I recommend, not add prop(drv), but prop(raw) with prop(fin)

    =========

    the same logic should work, even though you do not add prop(fin) = final value of the prop but keep to use shapekeys[prop].value as prop(fin), when prop.dsf have morph data. (delta verts infomation)

    so if there is morph data in prop.dsf, you use shape key as finalvalue. then all shapekey[prop] need to set driver, if there is no other prop which drive the prop(fin) >>> shapekeys[prop]. it have driver expression,

    shapekey[prop].value = prop(raw)

    I understand most of case, you actually add prop(raw) as user UI controller. then if user not change the raw value (like JCM, or MCM, we usually not input value), you do not need to generate prop(raw) so it work. (why I recommend to add raw(prop) in UI as hidden, for JCM and MCM, If make so, we do not need to check it is jcm or it is morph controller etc.. if it is hidden , just need hidden category, with default close those. then we can still adjust JCM, MCM when user need, and can set driver with use one logic. for shapekeys[jcm] or shapekey[mcm].

    Though I do not know if it cause heavy performance issue or not. then as I said, for JCM, we do not set raw value. so we do not need to add jcm[row] etc.

    but use same logic at least for property (not bone transform property), we can add driver with same logic for prop(fin) only. then always prop(law) can free move. at that time prop(law) never described in another prop driver expression. each prop(fin) only include self prop(raw) as first variable. then add (1st stage) , next mutliple with other prop(fin)

  14. Xin

    The advantage of setting up drivers without python is that Blender can execute them faster and that you wouldn’t run into weird dependency problems since Blender has a much clearer access to what the driver depends on, all of its inputs are explicit. Python can end up concealing inputs through dynamic objects. So getting rid of Python would make it easier in that sense. Blender would also warn you about dependency cycles in the console.

    To address the situation with EyeBlink, you could do the following: any slider exposed to the user is a new property, call them “EyeBlink_User”, “EyeBlinkL_User”. These are never driven, so you can tweak any “…_User” properties however you like. They are just top level inputs to the driver system. Since you execute everything without Python, speed doesn’t become an issue with a lot of intermediate properties because Blender can use multithreading. So the "..._User" properties drive internal properties called “…_Internal”, which in turn are inputs to other drivers according to their formulas:

    Bone Eye L = EyeBlinkL_Internal * 0.25 + 0.4
    
    EyeBlinkL_Internal = EyeBlink_User + EyeBlinkL_User
    

    Notice how, by using intermediate variables like EyeBlinkL_Internal you don't have to worry about "unwinding" the EyeBlink formula all the way to the bone to add it to the Bone Eye L driver directly. That's what I mean by intermediate values making your life easier. The formula says that EyeBlink affects EyeBlinkL, so you turn that into EyeBlink_User affects EyeBlinkL_Internal and you are done.

    This of course is not the exact same behavior as in daz but it’s not a problem in practice. What daz does is a so called "delta-add", which, in our example would be:

    Bone Eye L = EyeBlinkL_Internal * 0.25 + 0.4
    
    EyeBlinkL_Internal += EyeBlink_User (new) - EyeBlink_User (old)
    
    EyeBlinkL_Internal == EyeBlinkL_User
    

    With drivers, this would create a dependency cycle: EyeBlinkL_Internal -> EyeBlinkL_Internal -> EyeBlinkL_Internal -> ...

    This can be done with the "set" parameters of "bpy.props.FloatProperty" (a Python driver that calls an external function could maybe work too, but it would be quite ugly). I attached an example that does this. I don’t consider this worth the hassle (you would need to resolve dependencies yourself during evaluation and has some issues with keyframing). Letting it all be drivers means a reinterpretation of what sliders do. In Blender (while using drivers only) it means that each slider is an offset in absolute terms, and the offsets are added; while in daz dialing EyeBlinkL always means setting the final value, and dialing EyeBlink adds an offset to EyeBlinkL.

  15. engetudouiti

    Then I recommend, anyway when there is prop.dsf we at least add one prop(raw) as custom prop.

    then add prop(fin) will be decided, it have morph data or not only.

    you now not add prop(raw) for JCM , then for MCM (prop drive other prop) everytime you may need to thiink add prop(raw) or not.. then it make things more complex I feel.

    About bone transform props, at current we keep to use bone(drv) and bone(raw) as same as before. then the bone(fin) drive other props, we need to change it as bone(drv) transform value + bone(raw) transform value. (which we get as blender pose bone transform property for drv bone and deform bone)

    then as future if bone drive bone work well, it without use child relation, I may prefer, add bone(raw) with same hieralchy of bone(fin) = deform bone. then bone(fin) = bone(raw) + …… * …. with driver or constrain.

  16. engetudouiti

    I understand, we can not directly input final value as same as daz. with use raw value.

    daz auto set raw value, when we input final value or change slider. but Iwhen we import pose preset, or shape preset, daz discribe raw value only (I remeber so, need to check again though), then get final value with ERC formula, it will be shown as controller value.

    Then it only matter when user try to input final value directly. (I do not think it is important though, and actually there is no way, when final value is driven in blender, we can not input value directly)

    To think about UI, I may locate prop(Final value) without slider (with driver), then locate it right-side of the Prop (raw) controller (slider) in blneder UI , 2 props need to be locate on same row.

  17. Thomas Larsson repo owner

    OK, I think I get it. For each Daz property we need two Blender properties, raw/user and fin/internal. I didn’t realize that you could force a FloatProperty to update like that. Two questions remain though.

    1. What if the bone is not at the end of the chain but in the middle. As in the original bug:
    • facs_ctrl_EyeLookSide-Side drives facs_ctrl_EyeLookSide-SideLeft
    • facs_ctrl_EyeLookSide-SideLeft drives lEye?rotation/y
    • lEye?rotation/y drives facs_ctrl_EyeLookInLeft
    • facs_ctrl_EyeLookInLeft drives facs_bs_EyeLookInLeft_div2

    2 How do we make sure that the scripted expression is shorter than 256 characters? E.g., if I load all face units, expressions and visemes to G8F, the z location of lLipUpperInner depends on 85 morphs, most of them directly. The driving expression could be

    -0.001920*A-0.006604*B+...-0.000328*Z
    
    A = eCTRLAfraid
    B = eCTRLAngry
    ...
    Z = eCTRLvW
    

    Even if you use a shoehorn, the scripted expression can only depend on 53 variables before it exceeds 256 characters, so even if we only load the standard morphs that limit is violated.

    The dependencies for selected posebones can be viewed with the Utilities > Inspect Prop Groups tool

  18. engetudouiti

    About question 2, I think current blender limit is 512?

    https://developer.blender.org/rB6a0c18765307fba22a2fab78cadcabc73c9b10bb

    it seems once change as 256 then return it as 512

    though I do not know it may solve issue or not.

    About question 1,

    I may only consider

    • facs_ctrl_EyeLookSide-SideLeft drives lEye?rotation/y
    • lEye?rotation/y drives facs_ctrl_EyeLookInLeft

    Then describe drv bone rotation Y as lEye_drv.rotationY and lEye bone rotation Y as lEye. rotationY ,

    the lEye.rotationY is actually, lEye.rotationY(raw) value.

    As we know, the lEye.rotation Y is not final value. which we need to check. so real lEye rotation Y final value = lEye_drv.rotationY + lEye bone rotation Y

    so lEye_drv.rotation Y need to set driver, as same as before. (it is delta add?) , the driver target variable is

    • facs_ctrl_EyeLookSide-SideLeft(fin) value. with use same expression of ERC.

    then the final rotation Y value get same value as daz. (by lEye_drv.rotationY + lEye bone.rotation Y) it is auto added (because, you make drv bone as parent of raw bone = lEye bone.

    facs_ctrl_EyeLookinLeft_fin need to set driver expression, which include lEye.rotation Y and lEYE_drv.rotationY as driver expression variable.

    Do not think it work? (may need to check with actuall step value though)

  19. Thomas Larsson repo owner

    So I was not the only one who was affected by this limitation. But 256 and 512 is not a matter of principle, it only means that the limit will kick in later. If you add the FACS units and a couple of custom morphs, the expression may soon exceed 512 characters too, especially since you must switch to two-letter variable names after 52 variables.

  20. engetudouiti

    Yes I understand it.. (the limit problem, it only temporally easy limit, but not solve as true meaning)

    what I do not know clear. so evelmorph not work if you add all controller with raw and final? (final can be represent by shape key, when it change morph value)

    anyway if I write expression for lEye?rotation/y drives facs_ctrl_EyeLookInLeft

    facs_ctrl_EyeLookinLeft_fin = (facs_ctrl_EyeLookinLeft_row + bone_rotationY(fin)*step value + .,….) ) * 2nd staege multiple

    then you need to change

    bone_rotationY(fin) * step value, as (bone_rotationY(drv) + bone_rotationY(raw)) * step value , I think. actually you have done so. because we have only drv bone and raw bone. which we get the value. with UI (bone local transform)

  21. Alessandro Padovani

    Thomas, this is not really my domain, and I understand almost nothing of what you’re saying here. But, as a general suggestion, please consider that we don’t necessarily have to do everything daz does. I mean, if something gets extremely complex to implement, we can just set a limit to the importer, and document it in the known issues.

    An example is the daz morphing rig with genesis. Blender can’t morph armatures, so we use dbz to bake the actor morphs. This is a documented limit and a known issue. But it is acceptable and daz figures work fine enough in blender anyway.

    Just my two cents, again I’m definitely out of my domain.

  22. engetudouiti

    Please Alessandro you need not say it , why I try to add some infomation, it is just because Thomas hope to solve it. and he may only test with different version to avoid break add on.

    I or Xin never force it Thomas. eg I do not have interesting much about Fact morphs, but after all when it is included in this add on,

    there should be same report it not work with some props. so it perfectly depend Thomas how try to solve it or remain as same as before.

  23. engetudouiti

    What I still concern is, (not serisouly), actual pose bone transform value circulation. at current we represent it as (you had customized so for some bone related driver I think)

    we had used this simple formula, to get final daz bone.rotation(xyz)

    bone.rotation(x, y, z) = drv_bone. rotation(x, y, z) + child row_bone.rotation(x, y, z)

    for each xyz component, when we use the rotation value as driver target. (the rotation value drive other prop ) then when set driver for bone.rotation we only use drv_bone.rotation.

    but true value of daz bone rotation, may different for each X, Y, Z when we mix use both. But I just say it not show pefect same result, it not mean, I hope to make it show perfectly same as daz.

    (actually why Thomas add drv bone, it is my request, I really hoped I can still controll face bone, even though it is driven, so I do not expect, it work with mix use as same as daz)

  24. Alessandro Padovani

    engetudouiti, I am extremely grateful to you and Xin for your work. I believe it’s a great luck to have both of you here. It just rings when I hear Thomas talking of a major rewriting, because we know how hard it is to get things stable enough to work fine.

  25. engetudouiti

    Then sorry to add many,

    the expression may soon exceed 512 characters too, especially since you must switch to two-letter variable names after 52

    even though you divide prop as (prop(row) and prop(fin) it may not hard effect your current driver expresison limit I suppose.

    I think about face bone controlled by many props, because it seems most use letter I suppose.

    Then

    < prop2(fin)*step value + prop3(fin)*step value + …) (1st stage delta add) > * <propA(fin) * propB(fin) * propC(fin)….. (2nd stage multiple)> = bone(drv).rotation (x, y, z)

    is what we need to describe. for bone(drv).rotation x y z.

    as you can clear see, if you keep to use same variable as each prop (fin), there seems no difference. and actually about pose controller, I suppose we seldom see, 2nd stage ERC which drive rotation.

    I do not understand well how eval morph work, but if it have worked, I suppose you do not worry limit, even though you divide prop as row and fin. (about pose bone, after all we do not touch it, just change expression way if it need, but almost same I suppose) though I do not understand well about your evalmorph represent way, so I am sorry, if I say wrong about limit problem.

  26. engetudouiti

    Alessandro, I may hope to talk about this, even though it actually not work.

    as same as I frequently talked about daz bone set-up way, here or there. because so we can learn difference when we use add on in blender. and when there is clear way, we can solve it. about this case, I do not know. but it is not to show same UI as daz. it is to get same final value of morph when we use imported controller value. it is all. (The merit is, represent daz way, so we can directly use infomation of ERC more easy, but if it cause new issue, of course we can not, as Thomas said the Limit of expression is matter or I do not know detail Xin suggested way,, it beyond my knowledge.

  27. engetudouiti

    Then I see your doc (actually when I read it I did not read it carefully then now read again)

    so now you use custom function to represent expression right?

    https://diffeomorphic.blogspot.com/2018/04/custom-driver-functions.html

    https://docs.blender.org/manual/en/dev/animation/drivers/workflow_examples.html#driver-namespace

    in your doc, you solve the limit issue with make custom function. what I hope to ask is, so If you change prop as 2 prop (when it need only ), you can not use the custom function any more? (evalmorph) I suppose..

  28. Xin

    Thomas, that limit is another reason to use intermediate values and the “Sum Value” driver type (at least for long sums). You would set each term as input. Each of those terms should be calculated in an intermediate float array (as the first example did, see the picture attached in #393 showing a set up that never runs into a limit), so it’s just a simple sum at that point.

    Are there very long multiplications too? for those ones you can implement a chained multiplier with a float array property: first X terms are multiplied and outputted to index 0, next terms and index 0 are multiplied and outputted to index 1, … , final output is index N. All this can be made easy by implementing a class that takes care of setting up the drivers.


    As for the intermediate bone, you would have:

    facs_ctrl_EyeLookSide-SideLeft_Internal =  + facs_ctrl_EyeLookSide-Side_User + 
    
    lEye?rotation/y =  + facs_ctrl_EyeLookSide-SideLeft_Internal  +  
    
    facs_ctrl_EyeLookInLeft_Internal =  +  lEye?rotation/y + 
    
    facs_bs_EyeLookInLeft_div2_Internal =  + facs_ctrl_EyeLookInLeft_Internal  + 
    

    And the example with the update() for the FloatProperty was just an example, I hope you don’t bother with that, it has issues too (and quite ugly workarounds).


    In any case, I don’t think I have anything more to say right now.

  29. Thomas Larsson repo owner

    Xin, thank you. Everything is not clear to me yet, but this seems to be a path forward.

  30. engetudouiti

    If Xin way work well for 1st stage, 2nd stage multiple usually only used,

    1 to drive character specific morph ( JCM or MCM) by character morph value.

    2 to drive package morphs strength at same time by master control

    Unfortunately current add on daz rig hieralchy , pose controller can not manage well for multiple controller. when bone transform(fin) multiple with Value in daz, it circulate like this

    bone transform value(fin) = ( bone transform(raw) + bone transform(drv)) * Value

    bone transform(raw) reperesent, user add delta. bone transform(drv) represent, all 1st stage delta value which driven by other props.

    ERC describe the 2nd stage multiple as bone transform(fin) driver expression. But for blender add on we need to describe driver expression in drv-bone only.

    Then it auto circulated (child relation) as bone transform value(fin)

    bone transform value(fin) = bone.transform(drv) * Value2 + bone transform(raw)

    (raw + drv) * value = raw + drv * value2

    value 2 = {(raw+drv) *value - raw} / drv

    we need to use this value2 as multipler for drv-bone driver expression. when bone driven by 2nd stage controller (multiple with) >>>> it cause error. I suppose.

    ===

    we keep to use same value as drv-bone expression multipler, user need to understand, it not show perfectly same effect as daz. If user really want to get same effect, . manually multiple with (adjust raw bone ) by your self, or not pose raw-bone manually, but only use pose controller.

    As for me, it is not issue, but it may better described in somewhere after Thomas up-date morph importer.

  31. Thomas Larsson repo owner

    As I wrote in my blog, the morph system is now back, although there are still bugs, e.g. the original issue in this thread, One thing that I have come to appreciate with the simple drivers is that everything can be readily inspected in Blender, which should help when describing errors. There are a lot of intermediate properties, but if you only import a few select ones it may be manageable.

  32. Xin

    Oh nice, great news. That was very fast. Thanks again Thomas. This should be much easier to maintain too. I will test it later or tomorrow.

  33. engetudouiti

    Nest try may be,

    you can only import morphs of a given type (face units, expressions, visemes, ...) once. For custom morphs, you can only import morphs to a given category once. If you need to import more morphs, reimport the old ones too.

    I understand the reason, when we import new morph file, if it describe the ERC which drive,already imported morphs (save as controller), we need to serch all driven propertys, and change expressions for all.

    And it show why daz offer way to save driver expression as “Controller”, not only save as “Subcomponent”(driven property) Then vendor can add new controller dsf, which will drive other morphs without change other dsf driver expression.

    If all driver expression need to describe in sub-component (driven file) , when vendor offer new contoller as new product, it need to edit other sub-component dsf ERC (eg Daz official base morphs) , which are not include in the product package.

    I imagine, if there is way, to manage (describe and keep) all prop driver expressions like DAZ, When import morphs.

    Which can up-date, when user import new morphs later, and over-write expressions for related custom-props. but have no idea now how to make it work.

  34. Thomas Larsson repo owner

    I think the original problem is solved. If I import all face units and set the raw slider for Eye Side-Side = 0.3, the following final values are changed:

    Eye Side-Side = 0.3
    Eye Side-Side Left = 0.3
    Eye Side-Side Right = 0.3
    Eye Look-In Left = 0.45
    Eye Look-Out Right = 0.3
    lEye rotation X = -9 degrees
    facs_bs_EyeLookInLeft_div2 = 0.45
    facs_bs_EyeLookOutRight_div2 = 0.3
    

    which I believe is the correct behaviour.

  35. engetudouiti

    Thomas, I suppose we need not import G8 face unit, but only import FACS unit for G8.1, right? Then there still remain some problem about Eye relation morphs in FACS units.

    When l Eye Rotation added, it drive facs_ctrl_EyeLookInleft and facs_ctrr_EyeLookOutleft (in daz)

    You already set driver for facs_ctrl_EyeLookInleft(fin) but the driver expression is like this

    when prop drive bone >> add on can only drive drv-bone as the bone transform value.

    So facs_ctrl_EyeLookSide-SideLeft only drive lEyeDrv bone. then lEye bone transform value = 0. >> facs_ctrl_EyeLookInleft(fin) = 0 in blender.

    We remember same thing happend for jcm before, then you slove issue. the procedure must need When bone (transform) drive other props,

    you always need to set prop driver Expression Variable for bone and drv-bone. it must need.

    you need to add variable B , for lEyeDrv (Bone) X rotation. then mix A and B (basically I suppose you simply add A + B ) as Expression.

  36. engetudouiti

    Of course if at current Facs (G8.1) not support add Extra Face bone, it is not bug.

    anyway if I write expression for lEye?rotation/y drives facs_ctrl_EyeLookInLeft

    facs_ctrl_EyeLookinLeft_fin = (facs_ctrl_EyeLookinLeft_row + bone_rotationY(fin)*step value + .,….) ) * 2nd staege multiple

    then you need to change

    bone_rotationY(fin) * step value, as (bone_rotationY(drv) + bone_rotationY(raw)) * step value , I think. actually you have done so. because we have only drv bone and raw bone. which we get the value. with UI (bone local transform)

    Then If use 2 bone transform value for driver expression is difficult, I may suggest, not support driver work correctly when user add manuall facial bone posing. it can make things simple.

    Then all bone driver expression can exchange as BoneDrv transform value only. If you make it so, when user need to get same driver effect as daz, do not manually pose , facial bone. >> first use controller (it may only move drv-bone, then may driven other props, and may add shape key value ), after that adjust each bone without any driver effect. (about the case shape key not added with the new delta transform and may not drive other prop as same as daz.

    But I suppose it may not good, because, about Facial pose, we may main use pose controller (not directly change each facial bone transform), but about body pose, I do not think I main use pose controller at all.. but JCM or any bone transform drive props value still need to work.

    then I suppose we can not ignore, one of them (so need to consider, everytime, Bone and BoneDrv transform when it drive other props.

  37. engetudouiti

    Then it is not need to try soon, but if we really get the bone transfrom (x, y, z) about each component of bone in blender, which drive other prop,

    I think simply add “drv bone rotation X + child bone rotation X” may not show real bone transform value as same as daz. (I suppose you already notice it, but to make things simple at current just add 2 value)

    Because when we rotate drv-bone, the transform describe local axis of the drv-bone as zero local pose. then child bone just follow it, (no local transform value) then the child bone local axis change. To get real bone transform, we need to change as Matrix then return drv_bone local axis trnsform of zero pose. and get each x, y, z component I suppose.

    ideally,

    if you make function, which covnert, child bone local transform value ,as drv bone transform value ( only use drv bone local axis) with use 2 arguments vector, bone_drv (x, y, z) local transform , and child bone(x, y, z) local transform value, And use it as bone tranform value ( in driver expression, it may show more correct value when we mix use bone controller and manuall pose (child bone), I suppose.

  38. engetudouiti

    I consider the above, drv bone and child pose bone (raw bone) transform somehow serious. Because, when fin pose transform value (each bone Eular axis transform value) drive other props then finally effect shape keys to make facial pose. then use simplify circulation ( eg just add drv-bone and child bone rotation for each component,) the transform value should be different from daz transform value.

    It may only work, when drv-bone only rotate one axis, and child bone (user manipulate bone) rotate along the same axis.

    Of course if we only use eye-side to side, then rotate with the direction of child bone,, it work. but as real, , many facial morph try to rotate drv-bone for each axis, as they like. . then user manipulate child bone from current drv-bone position.

    So without we convert child bone local transform, as relative transform from the each drv bone rest pose, (pose local axis = drv bone pose local axis) and pick each x, y, z component, as transform value, there should be case,, user see different morph added when mix use pose controll + manuall child bone posing. (driven morph strength should be different form what it need)

    To avoid, it, I may prefer, Just use drv bone transform as driver expression variable, then not include child pose bone transform. (untill correct it)

    So there will be 2 option.

    option 1. not add facial bone. = not generate new child bone. then not rename . so all driver work. but user can not adjust facial pose manually. (all pose need to be made with controller only)

    option 2 add facial bone = generate child pose bone and drv-bone, as same as before.

    then if user not pose child pose bone manually, all pose controller work as it should be,, but user manuall pose delta is ignored. so If you keep to see reasonable shape key effect, with controller, only use controller. user pose bone transform is ignored from driver and driven shape key.

    (eg when we pose child eye bone to side directly, no driver , no shape key work actually about old add on, it had this issue.. then for temp solution, used drv rotation X + child bone rotation X as , delta transform rotation of the bone,. but actually it may easy cause issue, when pose bone transform drive other props.

  39. engetudouiti

    OK,, I think it is realtively easy to get correct x, y, z Euler rotation value of each child bone (relative from drv bone rest pose local axis )

    posebone.matrix_basis and mathutil module (Matrix, Euler).

    But I do not know, how I can include it as driver expression. Driver expression custom function can include, Mathutil toEuler etc?

    I have a few idea, how get it to work,, but if Thomas have some good solution,

    import bpy
    from mathutils import Euler, Matrix
    
    amt = bpy.context.active_object
    drv_bn = amt.pose.bones["drv_bone"] #driver bone (parent of user pose bone)
    raw_bn = amt.pose.bones["raw_bone"] #user pose bone(child of driver bone)
    raw_fn = amt.pose.bones["fin_bone"] #virtual bone to confirm script work
    
    drv_ao = drv_bn.rotation_mode  #Get Euler rotation order. for drv_bone 
    
    drv_mtb = Matrix(drv_bn.matrix_basis)
    raw_mtb = Matrix(raw_bn.matrix_basis)
    
    fin_mtb = drv_mtb @ raw_mtb
    fin_eul = fin_mtb.to_euler(drv_ao) #converted Euler rotation to use dirver expression
    
    print("fin matrix: ", fin_mtb)
    print("fin euler: ", fin_eul)
    
    raw_fn.rotation_euler[0] = fin_eul.x #converted Euler rotation(x) to use driver expression
    raw_fn.rotation_euler[1] = fin_eul.y
    raw_fn.rotation_euler[2] = fin_eul.z
    

    raw_bn is user pose bone, like lEye.

    drv_bn is drv bone. which will be driven by other prop like lEyeDrv when user add facial bone (all bones posable) option.

    raw_fin is virtual. I just add one more bone which simply copy the rest pose drv bone, to check script correctly convert, delta Euler rotation (drv bone and raw bone, raw bone Euler rotation cordinate system (Euler rotation local axis) change when drv bone moved)

    Now each bone local axis (for Euler rotation) describe as Axis(raw), Axis(drv), Axis(fin)

    Axis(fin) always same as Axis(drv). then Axis(raw) only change, when drv bone are driven, (rotate), then we can not simply add Each x, y, z component of Euler rotation, which use different local axis.

    This script convert, mix rotation ,(1st Euler rotation(drv_bone) and 2nd Euler rotation(raw_bone) which use different cordinate axis) as Euler rotation value which only use Axis(drv)

    The final Euler rotation (fin_Eul) represent Euler rotation in daz studio, when user rotate bone (include driven rotation value) .

    To get each x, y, z component, we simply use , fin_Eul.x fin_Eul.y fin_Eul.z

    then those value need to be used as expression variable, when bone rotation (Euler) x, y, z drive other props.

    Can Thomas do those conversion, when you add driver expression for driven property?

    I attach blend file (which already embed script), then you may confrim, after pose drv_bone and, raw_bone,, then run script,, the fin bone locate perfect same place as raw_bone. then the Euler x, y, z value (rotation value) with Euler in blender Transform with each rotation order is values we need to use for driver expression when bone rotation drive other prop.

    (of course it only need when user add drv_bone and pair child free pose bone)

  40. engetudouiti

    when you clear pose all bone,, they locate same place. (then fin bone and drv bone use same cordinate( axis of Euler)

    after you pose drv_bone and raw_bone, as same as we may do for import rig bones, then run script. fin_bone locate same place as raw bone. it represent, how bone rotate in daz (with driver, and user add rotation). then the fin_bone rotation value (Euler) is what we need to use for driver expression.

  41. Thomas Larsson repo owner

    Adding an extra bone seems like a high price for very little gain. It is important that the drv-bone behaves as in DS, since it is affected by morphs, but moving its posable child is done in Blender. I will go for the two-variable solution. The case that the morph is imported when the drvbones already exist works now, but remains to change existing drivers when bones are made posable.

  42. engetudouiti

    Thomas, No. I do not plan to add new extra bone. (the fin bone is only added to show how mix rotation work, and to confirm the conversion rotation value, script work correctly)

    You may notice, to get the final value , fin_eul (euler) do not use the “fin bone “ at all. but just use drv_bone and child pose bone(I name it as raw bone) then get the fin_eul. Then there is no need to add new bone.

    I just added it to confrim, then actually set fin_eul rotation value, for the virtual bone, in blender, then confrim the conversion formula work correclty.

    So to get conversion rotation value, (fin_eul.x , fin_eul.y, fin_uel.z), we need not add new bone. (and there is no reason we may need to add it, though if we add it, it may show us the rotation value, directly.

    But I may plan to add new custom props , like raw_bone[“fin_eul_x”] = fin_eul .x for each child pose bones when it have parent drv_bone.

    if it have no drv_bone,, raw_bone[“fin_eul_x”] = raw_bone. rotation[x] (euler)

    But I do not know , the bone[“fin_eul_x”] value can update,, when I pose the raw_bone. (and drv_bone will be rotated by other prop) (it need to update), do you think the new custom prop will auto up-date?

    If it work, I suppose when bone rotation drive prop, prop driver expression can directly use those converted rotation value. as same as lEye rotation X, Y, Z value.

  43. engetudouiti

    So the conversion script is

    amt = bpy.context.active_object
    drv_bn = amt.pose.bones["drv_bone"] #driver bone (parent of user pose bone)
    raw_bn = amt.pose.bones["raw_bone"] #user pose bone(child of driver bone)
    
    
    drv_ao = drv_bn.rotation_mode  #Get Euler rotation order of drv_bone 
    
    drv_mtb = Matrix(drv_bn.matrix_basis)
    raw_mtb = Matrix(raw_bn.matrix_basis)
    
    fin_mtb = drv_mtb @ raw_mtb
    fin_eul = fin_mtb.to_euler(drv_ao) #converted Euler rotation to use dirver expression
    

    Then the fin_eul.x , and fin_eul.y, fin_eul.z is mix rotation value which converted as one rotation which use drv bone local axis Euler rotation.

    so we do not need, just add bone.rotation[x] + boneDrv.rotation[x] any more. (it is wrong) but use the fin_eul[x]

  44. engetudouiti

    So what I means, we can convert mix rotation (Euler) values,, (drv bone rotation (euler) X, Y, Z, and raw bone rotation (euler), x, y, z which add on currently generate and need to use them as driver expression variable) as one Euler rotation X' Y ' Z' (which use same local axis as drv_bone) byt the conversion formula.

    But I still do not test with,, new custom property, then can not confirm, it can auto circulate when drv_bone and pose bone rotate. Without it, I can not include those new rotation value as driver expression variable.

    Do you think, you can embed those conversion process as Driver Expression ? (use Custom function etc)

  45. engetudouiti

    I afraid if Thomas still do not know what I means ^^;

    The problem is related this issue, https://bitbucket.org/Diffeomorphic/import_daz/issues/296/making-bones-posable-results-in-wrong

    it is case, bone rotation drive shape key or other props. (after all it is same, about how set-up driver expression when drv_bone and child bone rotate,, and rotation value drive other prop (or shape key)

    So those conversion is only need, when bone pose transform (rotation, translation) drive other props.

    In the linked issue, you simply add each bone rotation value as final rotation value. (for easy fix, I recommend so,, )

    A = drv_bone.rotation[x] , B = bone.rotation[X], then A + B

    but to get real fin rotation value, we need to convert Euler which rotate with different cordinate axis. (drv bone local ,and child bone local) >> one Euler rotation value. (with drv_bone local cordinate axis)

    The above conversion actually do it.

  46. engetudouiti

    OK now I test again

    after add Extra facial bone >> import FACS Unit only >> make all bone posable. it change driver expression of facs_ctrl_EyeLookInleft(fin) like this

    About this case,, when we do not use controller (facs_ctrl_EyeLookSide-SideLeft),, but manually rotate lEye bone as X axis (local),, no value added for the facs_ctrl_EyeLookInleft(fin) = 0

    then when you will solve issue, you had been added new variables B as leye Bone X rotation (Auto Euler), then Expression may change

    -2.865A (only count drv-bone rotation) >>>> -2.865(A + B ) (try to mimic sum rotation)

    Then what I mentioned above,, you may need not new variable, but directly use lEye[“fin_eul_x”] as new variable A', then expression change as 2.865 * A' and about the case you can not use Transform channel, but may use Single property = lEye[“fin_eul_x”] for the Variable A'

    I suppose you may only need to make Fin_Euler as [x, y, z] which circulated abovoe conversion function, as same as other DazXXXX prop of the bone. I suppose.

    I may try , actually generate those new Fin_Euler prop for child pose bone, (when it have no drv_bone, Fin_Euler rotation value = the bone rotation value of Euler (we see value as transform channell), then when it have drv_boen as parent, circulate Fin Euler, by attached script covnersion.

    Then test, actually the value will be up-dated correctly, when I use controller (rotate lEyeDrv , and manually rotate lEye bone) ,, I hope it work … without heavy issue.

    ===
    And if it work correctly,

    Though it is small thing, but ideally, I may prefer you keep same rule, to get facs_ctrl_EyeLookInleft(fin) as same as other visible props.

    it will include facs_ctrl_EyeLookInleft(raw) value in expression. (I understand, it is hidden so basically it should be 0, then you may need not for usual user work-flow.)

    facs_ctrl_EyeLookInleft(fin) = facs_ctrl_EyeLookInleft(raw) + (-2.865 * C)

    =============

    But for me it is not easy at all to generate new pose bone custom prop Fin_Euler ,which update value when drv or child bone rotate. so if Thomas have good idea,, I really expect it…

    I think I can do almost same thing like this,, (though I still not test if it work correctly) with use custom fuction as driver expression (so without add new bone prop)

    https://blender.stackexchange.com/questions/180926/driver-expression-dot-product-function

    2 answer of the link seems like what I need to make such driver .(mix 2 Euler and convert ,then get final rotation Euler for each X, Y, Z.

    ===
    And I may test Animation node add on, (I suppose if it can easy convert those vector, and can add driver,,)

    https://docs.animation-nodes.com/documentation/introduction/interface/

  47. engetudouiti

    Yes I suppose I could manage it. we only need to add new custom function first.

    import bpy
    from mathutils import Euler, Matrix
    
    def Daz_eul_conv(drv_bn, raw_bn):
        drv_ao = drv_bn.rotation_mode
        drv_mtb = Matrix(drv_bn.matrix_basis)
        raw_mtb = Matrix(raw_bn.matrix_basis)
        fin_mtb = drv_mtb @ raw_mtb
        fin_eul = fin_mtb.to_euler(drv_ao)
        return fin_eul
    
    bpy.app.driver_namespace["Daz_eul_conv"] = Daz_eul_conv
    

    Then I add new 3 props for raw pose bone (user pose bone child of driver bone)

    fin_eul_x, fin_eul_y, fin_eul_z. Then set driver for each x, y, z value, like this

    So I can now use these fin_eul_x , fin_eul_y, and fin_eul_z value, as mix rotation (euler) value, when it drive other props directly. Though I do not know, if it cause heavy pefromance issue, if add on generate those new euler props for pose bone (when it have drv_bone)

    The 3 custom fin_eul x, y, z, auto-update, when drv-bone or raw-bone rotated. and show Euler rotation value correctly. (mix as one Euler rotation which use same local cordinate axis as drv_bone)

    maybe I can enhance the custom function, more flexible. but basically it seems work (Add on can manage mix rotation when it drive other prop. with add new custom function for driver name space.

    (of course for real usage , we need not add new custom props, I just add them then set driver for it, to check custom function work correctly. But for add on , we can directly use the az_eul_conv(drv_bn, raw_bn), as the child bone, rotation Euler in driver expression.

    eg

    set variable A (drv_bn) and path as lEyeDrv.. set varialbe B ( raw_bn) and set path as lEye of rig.

    facs_ctrl_EyeLookInleft(fin) = facs_ctrl_EyeLookInleft(raw) + (-2.865 * (Daz_eul_conv( A, B )[0])

    I think these conversion should offer more good JCM effect. or such shape key which will be driven by bone transform (rotation).

    I may expand it, when transform include translate value, if I can enhance custom function. then can get x, y, z translate value,,, when it drive other prop…(basically it may need not, because I do not have such product morph, bone transform (translate x, y, z) move other prop, or shape key,, when I check sub-component,,, Though I do not know daz morph vendor may offer such expand JCM for breast adjust etc,,)

  48. Thomas Larsson repo owner

    OK, now I understand what you are saying. This needs to be thought about though. One of the nice things with the new drivers is that there are no custom python expressions anymore, so you can send your files to a render farm without including the stripped runtime system. That would be lost again.

  49. engetudouiti

    Yes I thought it need to be consider. I expect it may not drastically change pefromance, (because only when bone drive other props, this custom function will be used for the expression) but make defficult to send renderferm seems important

    I do not think,, blender offer expression function can manage Vector etc,,, so Custom Script must need to get this conversion. (or if there is way, I hope to know)

    I can not prefer which is important. it may change what user may expect.

    eg user who may not mix use pose controller and manual posing, this problem never happen. but if mix use both, all JCM which driven by bone rotation , get merit of this conversion. (though I seldom import body pose controller,, only import face pose controller,,)

    Actually I have ignored it (though I suspected,, the driven value should be different when we use simple add ,, I did not think, it can be converted easy with custom function.

    If user hope to keep full new Facs morphs effect for G8.1, , with drv and manuall posing , this conversion must need at least for eye bone. (actually eye drv bone often rotate up-down and side , then when 2 axis rotation added for eye_drv, , manuall posing bone rotation Euler cordinate , X or Z never along with drv bone axis, any more.

  50. Thomas Larsson repo owner

    Implemented in last commit. One problem is that the function is called three times, once for each component.

  51. engetudouiti

    Thanks, I do not understand perfectly, why it need to be called three times,, (maybe the function return Euler, then may need to be loaded for all components?)

    But if you make 3 custom function, for (x, y, z) component, then return each component rotation value, and use it for expression, may not call 3 times? Though I do not know if it cost more performance.

    +def Daz_eul_conv_x(raw_bn):
    +    drv_bn = raw_bn.parent
    +    fin_mtb = drv_bn.matrix_basis @ raw_bn.matrix_basis
    +    return fin_mtb.to_euler(drv_bn.rotation_mode)[0]
    

    or you may include the component as axis index (0 , 1, 2) as 2nd argument of custom function

    def Daz_eul_conv(raw_bn, idx):
    +    drv_bn = raw_bn.parent
    +    fin_mtb = drv_bn.matrix_basis @ raw_bn.matrix_basis
    +    return fin_mtb.to_euler(drv_bn.rotation_mode)[idx]
    

    Then return rotation value for each component, and use it for each rotation, may not call 3 times for each component? you may use it like this,,

    facs_ctrl_EyeLookInleft(fin) = facs_ctrl_EyeLookInleft(raw) + (-2.865 * (Daz_eul_conv( raw_bn, 0 ))

    (I test atcually set Daz_eul_conv( A, 0 ) as driver expression , then it return X rotation..

    when I modify expression as Daz_eul_conv( A, 2 ) it return Z rotation.. (though I think you need to make it work script auto set the arg and generate expression.. but about variable A keep to use same drv_bone path. I suppose

  52. Xin

    There is no reason to use Python functions here. The transformation can be expressed in Simple Expressions too. I will look into it later hopefully, but this is a simple expression under the hood.

    I think a general philosophy going forward should be to avoid Python in drivers unless there is no other choice, and even then the gains should be considered to see if it’s worth doing. Adding Python to drivers is not only bad for performance it’s also bad practice and will eventually end up blowing up in the form of update issues.

  53. Thomas Larsson repo owner

    Well, I got rid of the custom functions, so no need to include a stripped runtime system again. The final euler value is given by an expression like

    (self.parent.matrix_basis@self.matrix_basis).to_euler('XYZ')[0]
    

    and the Use Self checkbox is enabled, so self is the posebone.

    engetudouiti, the above expression computes the entire euler, and then just picks one component. Since we create three intermediate properties that hold the components, the calculation of the euler is repeated three times.

  54. Thomas Larsson repo owner

    The old way of just summing the Euler angles have been brought back. The option Combine Driver Matrices chooses between adding Euler angles and multiplying matrices. If somebody has a better name for this option, I would like to hear it.

    Note that the difference only matters if two Euler angles are large. Multiplying two matrices along the same axis is the same as adding the angles, even if the angles are large.

  55. Xin

    I think it’s possible to avoid doing the calculation with drivers by using bone constraints. The set up is the following (for the attached example at least):

    root → Drv → Raw
    But also:
    root → Fin

    Now set up a constraint for the Fin bone: Copy Transforms (or Copy Rotation) from Raw, where the Target Space is “Pose Space” and the Owner Space is “Pose Space”.

    Now you can use the after-constraint transforms of Fin as inputs to Drivers, by setting Driver variables on Fin, and selecting “Local Space” as the Space for the driver variable. This gets rid of any Python issues.

    Note that this example is using a simplified rig, but I believe it’s possible to do a similar thing for a general rig. That is, using constraints to get the transformation on a bone, and then get the transformations from that bone.

  56. engetudouiti

    Thomas thanks. I did not think we can use matrix math in driver expression directly, without python function. So if it work , no problem. new converted fin rotation value should show real rotation value for bone which will drive other prop, as same as daz.

    at same time, there seems a little difference, how you use the converted rotation value (circulated by matrix_basis of 2 bone) from what I suggested.

    Because,, I may not use it directly for each raw bone component . the conversion rotation value only need to be described for driven prop driver expression.. about the case we can not use self I suppose. You seems actually add new custom property for raw (user pose bone child of drv bone) , then use it for driven prop expression?

    Anyway so driver path can set any porperty . like matrix_basis, or bone as we need, (I did not notice it) there seems many variation, to set driver expression which include converted Euler rotation value.

    eg now in daz boneA X rotation value will drive PropB(fin).. then I may set dirver for PropB_fin , like this

    Expression is

    A + (raw_bn.matrix_basis@drv_bn.matrix_basis).to_euler(drv_bn.rotation_mode)[0] * 0.2

    A = propB(raw) value. of propB (which is driven by bone rotation)

    raw_bn.matrix_basis@drv_bn.matrix_basis).to_euler(drv_bn.rotation_mode)[0] = bone euler X rotation (fin)

    0.2 = step value. of delta add ERC.

    There seems too many variation, eg, I could directly assgin variable raw_mtx as pose.bones[“raw_bone”].matrix_basis, but about the case, we can not set pose.bones[“raw_bone”].rotation_order. so I set bone as varaibles. then embed in expression.

    pose.bones[“raw_bone”].rotation_order return set value index when I assgin it as variable then it can not work. so I need to set Bone as variable. then can use Bone.rotation_order, directly. (it seems kind of blender side bug, I feel)

  57. engetudouiti

    Xin of course, I think you may find new smart way which use constrain . But the reason I do not push the new rig system, is same. Change rig hieralchy as new constrain, is really heavy up-date than use new morph system. it may need another branch untill finish all. eg at current MHX converted rig is very stable. as real usage, I mainly use MHX rig.. so if use new hieralchy it effect, MHX conversion too.

    If you plan to new rig system, I think we may better separate topic.

  58. Xin

    It’s not a new rig system. See the attached .blend. It’s merely using bones to get transforms from them for the drivers, sidestepping the need to use “Slow Python Expressions”, which make the addon quite useless for render farms and will eventually become an issue performance-wise (on top of the very likely updating issues you will encounter later on with more drivers now that the addon uses a lot of intermediate properties). The bones can merely be used for the drivers, they don’t need to be part of the skinning hierarchy at all.

  59. engetudouiti

    Xin If it work well no problem for my side. at same time I may approve

    Adding an extra bone seems like a high price for very little gain. It is important that the drv-bone behaves as in DS, since it is affected by morphs, but moving its posable child is done in Blender. I will go for the two-variable solution. The case that the morph is imported when the drvbones already exist works now, but remains to change existing drivers when bones are made posable.

    As for me, get correct rotation Euler value and use it to drive custom props or shape key was only mater, then if Thomas check your way, then can solve it without serious problem, I apreciate.

  60. Thomas Larsson repo owner

    Implemented in latest commit. It seems to work quite nicely so far, both if you add morphs (eye-side-side or eye-up-down) before or after adding the extra face bones. It will not work with rigify yet, but it does work with mhx since it modifies the existing armature. Or, Blender complains about dependency loops, which has something to do with the track-to constraint from the eyes to the gaze bone, but that is a separate issue which was there before.

  61. Xin

    Thanks Thomas, I will look into it later or tomorrow to see if there are any issues with this and if it can be simplified further.

    Also, instead of the Copy Transforms constraint, which copies everything, it might be better to just use the Copy Rotation constraint, since we only care about angles here.

  62. Alessandro Padovani

    Personally I don’t like the fin bones layer. Using extra bones to simplify drivers seems quite “borderline” to me. It’s not what bones are for. Though I understand complex rigs may use many bone layers, I wonder if this is really necessary to “just” drive morphs.

    Then I’m not a rig expert at all and I understand may be 1% of what you’re saying here. I just wanted to drop a “view from outside” to you tech guys.

  63. engetudouiti

    Alessandro it is not difficult tech things, you can understand easy why it need when rotation value drive props (like JCM or FACS morphs)

    When you pose eye, with controller and adjust it with child bone pose, driven corrective shape key auto added with driven strength value, then deform your character face. (if you import Facs morph , you may hope to use daz offer corrective morphs correctly, it try to adjust eye around mesh with eye rotation value)

    so for user who import corrective morphs, the correct rotation value is real matter.you may not hope to set different value for corrective morphs. The morph will be auto added then you basically can not adjust it.

    As you said the value “just drive morph” but the auto circulate value decide corrective morph strength. then if wrong value,(auto circulated) is used, it show different deform for corrective morphs. = the Corrective morph may change as random morph. (some case it may change as wrong corrective morph, at least we can not expect, those corrective morph work as it need)

    I expect new blender node system may offer more flexible driver , not need to add new bone and constrain only to represent driver circulation. but at current this way seems best for me.

  64. engetudouiti

    About OP issue, add on not use Eye Look Automatic property (bool), which can ON OFF some eye look morphs. with eye rotation. but the prop will be imported as float props (maybe it no drive other morphs?) . I do not care it, but sooner or later 8.1 user will report it I feel.

    The prop is set as ON (1.0 or True) as default G8.1, then use 2nd stage multiple to on and off. for these facs_ctrl_eyelook XXXX, just multiple with 0 or 1, then it seems not so difficult to make it work with add on?

    The Eye Look automatic have no Controller, so you may not need to generate EyelookAutomatic[fin] (though it may not cause any harm for us)

    anway if you use EyelookAutomatic[fin] ,, the boolean float value need to be mutlipled and described in driver expression of facs_ctril_EyeLookXXXX [fin]

    (ideally, if you can generate bool type prop, when we import these bool daz prop, it make UI fine I think, I like to import custom boolean button ^^; )

  65. engetudouiti

    btw with test recent commit , it seems some how miss use new Xin fin bone rotation value in driver expression.

    you see this pic , it is expression with use new fin bone rotation value. the problem is you still add eye bone rotation X with use the eye bone local cordinate axis.

    Though I do not check new Xin constrain way , but I simply suppose it show same result as use custom function. then if it work so, it should use drv-bone local cordinate Euler rotation for the value. so this expression still use 2 different local axis rotation and add. at least you can not include the lEye Euler rotation value. without you convert cordinate axis, as drv bone.= daz bone cordinate local axis.

    I suppose you may need not include the eye bone euler rotation value anymore. I think Xin way represent rotation value already include the lEye rotation. (but only use drv bone local cordinate)

    or if Xin converted rotation value only represent, lEye rotation value but convert as drv bone cordinate, then you may need to add drv_bone Euler rotatiton value. About both case current setting is wrong. Actually I am not well understand Cosntrain option, (but can easy suppose how xin convert the mix rotation), so you may better check again (some simple miss seems occured when merge new option I suppose)

    Then add new multiple for facs_ctrl_EyelookAuto seems easy for user side.. and it work well. (only multiple with in current expession of facs_ctril_EyeLookXXXX [fin], I actually added them, then notice this issue. (include lEye rotation with use the cordinate (it change with current drv-bone)

    And I suppose correct expression should be

    A = facsCtrlEyeLookinLeft (raw),, C =acs_ctrl_EyelookAuto(fin)

    Then facsCtrlEyeLookinleft(fin) driver expression = (A+(-2.865*B) ) * C

    You generate facsCtrlEyeLookinLeft as hidden props (so I can find those custom props and expect it drive fin value as same as daz hidden parameters)

    but even though I change the value, it not added. (without you modify so) , you already generate it so I may recommend anyway use it for fin value. (eventhough basically it just keep default import value, and most of case keep 0)

  66. engetudouiti

    Then if we need to still include eye (child driven bone) Euler rotation, in expression, then add with another rotation value, after all the new procedure not work correctly.

    because,, it may convert mix rotation value which use child bone cordinate.

    Though if Xin really do complex thing, it may work. but with see this expression, and actually it seems need to keep the Eye rotation value to get effect , I suppose the final rotation value use child bone local cordinate, not drv bone codrinate. then get mixing value. if so it remove all meaning what you have tried. as principle, we need to get rotaiton value, with drv bone coridnate.

  67. engetudouiti

    So I download xin file, and confirmed it is what I supposed. all bone hieralchy is same as my blend file, which I add conversion script with virtual fin bone.

    xin blend file fin_EulerRotX, Y, Z already include the raw bone rotation with correct cordinate (same as drv bone cordinate with rest pose).. so the expression conversion seems change without Thomas intention some where. if you correctly pick fin bone rotation value. you need not include eye(raw) bone rotation in driver expression variables any more.

  68. Thomas Larsson repo owner

    engetudouiti, your problem three posts back should be gone now. I didn’t check the case of adding a property that is driven by a bone, after the drv bones were created. It only happens for the facs morphs among the standard morphs.

    Also, I think that the intermedate properties can be eliminated altogether. Whenever something is driven by a bone channel, just replace the bone with the corresponding fin bone.

  69. Thomas Larsson repo owner

    Allowing the raw limits outside the daz limits can lead to problems. Consider the facs units Jaw open and Mouth close. The final value of mouth close (= the shapekey value) is the product

    MouthClosed(fin) = MouthClosed(raw) * JawOpen(fin)
    

    MouthClosed(fin) cannot exceed 1, but if JawOpen(fin) < 1 we can make it too big if MouthClosed(raw) > 1. If MouthClosed(raw) were also limited, we would avoid this problem.

  70. Thomas Larsson repo owner

    We also have some problems with facs expressions ruining facs units. The new morph system first removes all morphs of the given type (units, expressions, etc), then reads the files and creates the morphs again. This is normally not a problem if you load all morphs of the given type. However, it only works as long as morphs of one type (facs expressions) don’t refer to morphs of another (facs units). Don’t know how to handle this. Perhaps both types need to be loaded at the same time.

  71. engetudouiti

    About multiple (2nd stage) limit issue,, I think DS have almost same problem. at same time I may not try to set limit for raw value. but just use Fin value limit,

    MoutClosed(Fin) shoud have limit for minus side too. (0 or -1)

    so how you set large or small value for jaw Open actually mutlipled value will be stop by MoutClosed(Fin) limit.

    it is same as daz multiple controller and subcomponent fin value. if you limit for propA raw, prop Fin will be limitted. more narrow.

    in this pic I set min and max PropA (fin) and propB(fin) -2 to 2

    then set multiple as 2nd stage, PropA = PropA(raw) * prop(B)

    If I set prop(B) = 0.5.

    You may see raw value is no limit (about this case it show as -7.1 ..) , but just multipled with prop B value 0.5 .. -7.1 * 0.5 = -3 but PropA have limit, then it force to stop as -2.0

    If you set limit for the Raw value in blender, as -2 to 2.. you can not set Fin value as 2. so to it work you may set min and max as -4 to 4.. but if you use 0.25 for prop B, In daz raw value have no limit, then we can set raw as 8, = we can set propA as 2.

    So actually if you set limit for A raw value, you make your morph set very narrow range. when it will be multipled with oher prop B,, if you set propB as 0.01,, propA fin value only work between -0.01 to 0.01 etc. (you can not change propA value as 1, any more)

    If you see strange deform, you may need to check raw value too. but to avoid the issue, you may better not use limit for raw. Actually multiple case may show more issue, if you set limit for raw as same as fin.

  72. engetudouiti

    Then actually I suppose we have set limit long time for all raw value .. because you had circulated as internal fin value,

    but all slider was actually raw value slider. there have been no fin slider (we can not make it when fin value is driven) , at same time you have set limit for all slider(raw) as same as (fin), then it have narrow range problem.

    I have seen the issue sometimes, but it might need longtime to tell why it is problem Now we see hidden problem which user have not noticed clear. (or simply avoid to talk about it. it is complex ) I feel.

    So if user hope to keep old behavor, user may set limit for raw value. but if you hope to use full range of morphs, with mixing slider, I may recommend you can not set limti for raw. or slider range easy limit really narrow when it will be multipled, (user may do not know )

  73. engetudouiti

    About 2nd issue, can not you change this behavor?

    The new morph system first removes all morphs of the given type (units, expressions, etc), then reads the files and creates the morphs again.

    The reason why you need to so,, you may try to set driver expression, when generate custom props, by one step when you load (read json) file?

    As test purpose… (you may test only) I may think another way,,,

    I may first generate all props (raw slider and fin, and shape keys data in each dsf), which user checked first. if there is shape key data in dsf, which should be controlled by morph(fin) value, then add driver for shape key. but not generate any other driver about this First stage.

    First>> generate all props (raw and fin) and shape key(with fin driver) only about morphs user checked. without use formula.= non additional driver. so now there is only raw, fin, shape-key,, for all improted morph (user check about the category) then each fin morph have driver expression like this, (it not matter, the prop is hidden or not ), use one rule make things simple, I feel…

    each morphA dsf generate , (sometimes shape key too)

    morphA(fin) , morphA(raw) (slider), and shape key A (when dsf include vertex delta data)

    morphA(fin) have driver, which only describe morphA(fin) = morphA(raw)

    then shape key A have driver which only describe, Shape keyA value = morphA(fin).value

    This is all step add on do as First step.

    Second >> set driver expression for each props relation for all morph(fin) .

    with read each morph dsf> formula section. one by one again. (if there is prop, which not imported in blender, you may show info in console, then pass the prop, but add the prop in expression only use prop which already generated in blender,,

    do same thing with each prop = each dsf reculsive…(read and get formula in dsf, serch props in blender, add new prop or multiple the value)

    But How you make it work for Second step,, I do not have clear design now,, even though it take more -time to generate driever I think it seems more reliable.

  74. engetudouiti

    btw

    Also, I think that the intermedate properties can be eliminated altogether. Whenever something is driven by a bone channel, just replace the bone with the corresponding fin bone

    Yes . I thought same thing, when you add intermediate props. though it seems good to confrim process one by one. but actually you need not add new rot props . you can directly use fin bone transform rot x, y, z. , which alreaady show mix rotation value, and can set it in expresison ,variable directly. (use transform type). you seems already remove it though.

  75. Thomas Larsson repo owner

    Limits for the raw and final properties can now be set independently, to either DAZ, custom, or none. Personally I prefer to use DAZ limits for both raw and final, so that is the default.

  76. engetudouiti

    Thomas if you remain both option it is not problem for me thanks. But in daz, you can make this pose

    I suppose if you set same limit for raw and fin about Mouth close (min 0, max 1), then set Jaw open 0.15 , , you can not over 0.15 for Mouth close anymore.

    In daz which value you set for Jaw open, if it not 0, (0.1 or 0.3 etc),, you can still set Mouth close from 0 to 1. jaw open limit not effect for Mouth open.

  77. engetudouiti

    Then I understand, when control fin value by raw slider, no limit not offer good adjusting. But I feel when you controll Jaw Open or mouth close, you may see un-natural deform with current value setting. but I think the behavor is almost same as daz for me. after all, I controll Mouth close (which is multipled by Jaw Open) fin value, from 0 to 1 range. raw value slider need to set no limit to make it work. I feel.

    Maybe I think Thomas feel mouth-close strength should not over jaw Open value. then you feel , no limit cause strange deform. But If you set mouth open which controlled the effect limit by Jaw Open, the problem may more clear, when you mix other Face pose like Mouth Upper /Lower up and down. At same time, if we use no limit for raw, we must need to keep fin value as user check easy.

    I have one request to use easy no limit silder.

    all prop(fin) value = f(row). So we can get raw value, with fin value. (use driver expresison variable and expression formula) by python.

    If you finish morph work , I may hope you add small UI tool. witch can select prop, , user input value which user hope to set fin value,, ,, script circulate the raw value. from expression and each variable which currently set for the prop. then get raw value>>auto set the value for raw >>> it set fin value, as user need.

    How make it smart UI, is difficult, but basically we can make it, with simply dialogue I suppose. (may need set button and input prop I suppose)

  78. engetudouiti

    Thomas do you use SymPy? I suppose, if you can make your add on use sympy without user manuall import, and set sys path etc,

    it easy get raw value, with use blender expression and fin value. Only problem is, make user can use sympy module without import and set path for blender. At current, I do not think it seriously now,

    but if add on can use SymPy, it may expand much, I suppose. (user will input fin value , then raw value auto set >> fin value will be driven with current raw value.

    It is almost same what actually daz prop slider work.. I think.

  79. engetudouiti

    I actually test Sympy and Numpy functions, then we do not need these module to make tool which set Fin value. ^^; (I thought daz ERC too complex)Because, daz ERC only offer sum and multiple, it seems not so difficult. I thanks you keep raw and fin value props for default option still)

    Then Can you pick 1st stage delta values (sum) and 2nd stage multiple values from fin driver Expression, after you generate all driver, (by make new func etc) ?

    It seems no difference eather user use Evalmorph option (current default) or non python expression.

    Eval custom function seems only used to generate bone driver for drv-bone expression,, so the value already represent 1st stage delta sum . (and maybe I think you can not make it work when daz ERC multiple bone rotation, with raw bone and drv bone. It is current limit I feel or, user can not move raw bone any more), so we can ignore 2nd stage multiple for drv-bone I suppose (or you have already include 2nd stage multiple in eval function? I do not know)

    Anyway, all fin prop = {raw + (delta sum of 1st stage)) } * propC * prop D *propE…. (multiple values sum of 2nd stage)

    Prop (raw) = Fin - (drv delta) / C + D + E…… so we only need to get 1st srage drv_delta sum and C + D + E ( 2nd stage multipled value sum)

    (I often forget, if we have no 2nd stage multiple, the formula need to change, multipe sum as 1. , or you may input 0 and multiple with raw.. >> fin value set as 0..)

    Of course we can not set Fin value directly for the driven prop. But add set button (or icon) , then click it, open dialogue to input value, then it circulate raw value from user input value (which user hope to set as Fin value), >> set it for raw value.. seems nice tool for me. (It is not need to try to make new tool soon,, but I just memo here. )

    Though UI may need one more icon (button) on same slider row. which will open dialogue to set raw value from user expect Fin value (reverse circulation)

  80. Log in to comment