Arms Front-Back is not imported

Issue #1473 resolved
Rakete created an issue

When I pose a figure using the “Arms Front-Back” slider, then save a pose preset and try to load it into diffeo the arm pose is not applied to the figure. The morph is loaded and works though.

The reason seems to be a mismatch between the name of the modifier and the id of the modifier. See this section from the file data\cloud\1_42071\data\daz 3d\genesis 8\male\morphs\daz 3d\base pose\pctrlarmsfrntbck.dsf:

"modifier_library" : [
        {
            "id" : "CTRLArmsFrntBck",
            "name" : "pCTRLArmsFrntBck",
            "parent" : "/data/DAZ%203D/Genesis%208/Male/Genesis8Male.dsf#Genesis8Male",
            "presentation" : {
                "type" : "Modifier/Pose",
                "label" : "",
                "description" : "",
                "icon_large" : "",
                "colors" : [ [ 0.3764706, 0.2784314, 0.3254902 ], [ 1, 1, 1 ] ]
            },
            "channel" : {
                "id" : "value",
                "type" : "float",
                "name" : "pCTRLArmsFrntBck",
                "label" : "Arms Front-Back",
                "value" : 0,
                "min" : -1,
                "max" : 1,
                "clamped" : true,
                "display_as_percent" : true,
                "step_size" : 0.04
            },
            "group" : "/Pose Controls/Arms",
            "formulas" : [
                {
                    "output" : "Genesis8Male:/data/DAZ%203D/Genesis%208/Male/Morphs/DAZ%203D/Base%20Pose/pCTRLArmsFrntBckRight.dsf#pCTRLArmsFrntBckRight?value",
                    "operations" : [
                        { "op" : "push", "url" : "Genesis8Male:#CTRLArmsFrntBck?value" },
                        { "op" : "push", "val" : 1 },
                        { "op" : "mult" }
                    ]
                },
                {
                    "output" : "Genesis8Male:/data/DAZ%203D/Genesis%208/Male/Morphs/DAZ%203D/Base%20Pose/pCTRLArmsFrntBckLeft.dsf#pCTRLArmsFrntBckLeft?value",
                    "operations" : [
                        { "op" : "push", "url" : "Genesis8Male:#CTRLArmsFrntBck?value" },
                        { "op" : "push", "val" : 1 },
                        { "op" : "mult" }
                    ]
                }
            ]
        }
    ],
    "scene" : {
        "modifiers" : [
            {
                "id" : "pCTRLArmsFrntBck",
                "url" : "#CTRLArmsFrntBck"
            }
        ]
    }

(this is potentially a mismatch between the Daz connect install and the DIM install). The id is CTRLArmsFrntBck and the name is pCTRLArmsFrntBck and when I add some logs to the code that loads the pose I can see that it tries to load the pCTRLArmsFrontBck one: convertMorphAnim {'FBMHeavy': [[0, 1]], 'pCTRLArmsFrntBck': [[0, 1]]} but fails to do so because getFormulas returns None as formula, which causes convertMorphAnim to skip that property:

def convertMorphAnim(self, vanim, rig):
    [...]
    formulas,alias = self.getFormulas(rig, prop)
    print("prop", prop, frames, formulas)
    if formulas is None:
        if nonzero(frames):
            print("alias:", alias)
            self.used[alias] = True
        continue

So to solve that problem I changed getFormulas to just leave out the first character and try again when formula is None (and actually a bunch of other things, just because):

def getFormulas(self, rig, outerProp):
        outerAlias = self.alias.get(outerProp)

        lowerAltMorphsKeys = [s.lower() for s in self.altmorphs.keys()]
        lowerRigKeys = [s.lower() for s in rig.keys()]
        lowerShapeKeys = [s.lower() for s in self.shapekeys.keys()]
        lowerFormulasKeys = [s.lower() for s in self.formulas.keys()]
        lowerFormulas2Keys = [s.lower() for s in self.formulas2.keys()]

        def get(prop, alias=None):
            print("getFormulas", prop, alias)
            if prop in self.altmorphs.keys() or prop.lower() in lowerAltMorphsKeys:
                altformula = self.altmorphs.get(prop, self.altmorphs.get(prop.lower()))
                alt = list(altformula.keys())[0]
            else:
                alt = "*"
            if alias and (alias in rig.keys() or alias in self.shapekeys.keys() or alias.lower() in lowerRigKeys or alias.lower() in lowerShapeKeys):
                formula = {alias : 1.0}
            elif alias and (alias in self.formulas.keys() or alias.lower() in lowerFormulasKeys):
                formula = self.formulas.get(alias, self.formulas.get(alias.lower()))
            elif alias and (alias in self.formulas2.keys() or alias.lower() in lowerFormulas2Keys):
                formula = self.formulas2.get(alias, self.formulas2.get(alias.lower()))
            elif prop in rig.keys() or prop in self.shapekeys.keys() or prop.lower() in lowerRigKeys or prop.lower() in lowerShapeKeys:
                formula = {prop : 1.0}
            elif alt in rig.keys() or alt in self.shapekeys.keys() or alt.lower() in lowerRigKeys or alt.lower() in lowerShapeKeys:
                formula = altformula
            elif prop in self.formulas.keys() or prop.lower() in lowerFormulasKeys:
                formula = self.formulas.get(prop, self.formulas.get(prop.lower()))
            elif prop in self.formulas2.keys() or prop.lower() in lowerFormulas2Keys:
                formula = self.formulas2.get(prop, self.formulas2.get(prop.lower()))
            else:
                formula = None
            return formula

        def camelCaseSplit(s):
            matches = re.finditer('.+?(?:(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|$)', s)
            return [m.group(0) for m in matches]

        formula = get(outerProp, outerAlias)
        if formula is None and len(outerProp) > 1:
            formula = get(outerProp[1:])
        if formula is None and len(outerProp) > 2:
            formula = get(outerProp[2:])
        if formula is None and len(outerProp) > 3:
            formula = get(outerProp[3:])
        if formula is None:
            ccs = camelCaseSplit(outerProp)
            if len(ccs) > 1:
                formula = get(''.join(ccs[1:]))

        if outerAlias:
            return formula, outerAlias
        else:
            return formula, outerProp

(little bit on the crazy side, I know, but it works)

However, a proper solution should probably involve using the name instead of the id to look up the modifier? If that is even possible? I don’t know enough about either this codebase or how daz files are supposed to work to come up with a proper fix I am afraid, so at least for me, maybe that hack above is enough for now.

Comments (3)

  1. Thomas Larsson repo owner

    Fixed in last commit. As you noticed, a morph’s id and name sometimes differ. Both are used in different situations, so it not possible to only keep one of them. The plugin therefore keeps track of both in a collection property called DazAlias. The problem was that this table was used in the wrong direction.

    The definition of an alias is shown as a line starting with = in the terminal window when the morphs are loaded, like this:

     = pCTRLArmsFrntBck CTRLArmsFrntBck
     * ArmsFrntBck
     * ArmsFrntBckLeft
     * ArmsFrntBckRight
    

  2. Log in to comment