New buildBaked function not working for FBMHeavy (and other body morphs I assume)

Issue #1470 resolved
Rakete created an issue

You just commited new functionality to import baked properties. So there is now a function buildBaked which iterates through all formulas and does this:

ref,key,value = self.computeFormula(formula)
rig = inst.rna
if key == "value" and rig and value != 0:
    [...]

and I assume the point of this is that you expect to have character morphs applied to the figure like for example Aiko, which would have a property “Aiko Body” that applies the modifier “FBMAiko” with some value, so the formula then is “Aiko Body” * “FBMAiko” = “Baked figure”. So if the “Aiko Body” value != 0, then you create a property for FBMAiko and just put that value in.

But that does only work for properties that apply a modifier. There are also properties which apply to other properties, and in that case the FBM would be on the left side(?) of the *. So in case of FBMHeavy, you have at ton (one for each transform that is modified) of formulas like “FBMHeavy” * “Left Toe Scale”, and the code does not work because transforms like “Left Toe Scale” don’t have “value” as key, but something like “scale/x”, like here:

{
  'output': 'rPectoral:/data/DAZ%203D/Genesis%208/Female/Genesis8Female.dsf#rPectoral?orientation/z', 
  'operations': [
    {'op': 'push', 'url': 'Genesis8Female:#FBMHeavy?value'},
    {'op': 'push', 'val': -0.1359132}, {'op': 'mult'}
  ]
}

where self.computeFormula would return “orientation/z” as key and the if key == “value” check fails.

I don’t really know how a solution for this would look like, I thought maybe the code could just check there were many formulas for the same ref (since that would always be “#FBMHeavy” for all the FBMHeavy formulas), and then when none of them actually resulted in a pre-baked property, you could check if the value on the ref asset is != 0 and then just make a property for it?

And another thing I noticed that I am curious about: is there a way to get the actual zero value for the FBMHeavy asset? You compare with != 0, which works in 99% of the cases, but technically you should compare against the zero value that should be defined in the .dsf for FBMHeavy, because it could be something other then 0.

Comments (13)

  1. Rakete reporter

    I’ve been trying this and it seems like it should work in principle, I changed buildBaked so that it adds FBMHeavy property when the FBMHeavy asset.value != 0:

         def buildBaked(self, context, inst):
            rig = inst.rna
            print("buildBaked", rig.name, len(bpy.context.scene.objects), len(rig.DazBakedFiles))
            from .driver import removeModifiers, setProtected, addDriverVar
            from .morphing import setActivated
            def bake(ref, value):
                value = float(value)
                file,raw = ref.rsplit("#",1)
                file = unquote(file)
                raw = unquote(raw)
                rig[raw] = value
                final = finalProp(raw)
                rig.data[final] = value
                print("Baked morph (%s): %s = %f" % (rig.name, unquote(raw), value))
                setProtected(rig, raw)
                setActivated(rig, raw, False)
                item = rig.DazBaked.add()
                item.name = raw
                item.text = raw
                if file not in rig.DazBakedFiles.keys():
                    item = rig.DazBakedFiles.add()
                    item.name = file
                    item.f = value
                fcu = rig.data.driver_add(propRef(final))
                fcu.driver.type = 'SCRIPTED'
                removeModifiers(fcu)
                fcu.driver.expression = "a"
                addDriverVar(fcu, "a",  propRef(raw), rig)
            refs = {}
            for formula in self.formulas:
                ref,key,value = self.computeFormula(formula)
                if key == "value" and rig and value != 0:
                    bake(ref, value)
                else:
                    pushRef,pushKey = self.getRefKeyFormula(formula, "push")
                    #print(pushRef, pushKey)
                    if pushKey == "value" and pushRef not in refs.keys():
                        refs[pushRef] = formula
    
            for ref,formula in refs.items():
                print("ref:", ref, formula)
                asset = self.getAsset(ref)
                if asset.value != 0:
                    print("asset:", asset, asset.value, asset.id, asset.url)
                    bake(ref, asset.value)
    
    [...]
    
        def getRefKeyFormula(self, formula, key):
            if key in formula:
                return self.getRefKey(formula[key])
    
            for struct in formula["operations"]:
                op = struct["op"]
                if op == key:
                    if "url" in struct.keys():
                        return self.getRefKey(struct["url"])
    
            return "",""
    

    However this still does nothing because it seems while importing the rig is created and deleted several times, each times loosing properties that have been added. So I add FBMHeavy to rig.DazBaked, but the final rig does not contain it:

    buildBaked Genesis 8 Female.001 2 0
    ref: #FBMHeavy {'output': 'hip:/data/DAZ%203D/Genesis%208/Female/Genesis8Female.dsf#hip?center_point/y', 'operations': [{'op': 'push', 'url': 'Genesis8Female:#FBMHeavy?value'}, {'op': 'push', 'val': -1.757278}, {'op': 'mult'}]}
    asset: <Morph FBMHeavy 1.000000 0 0 None> 1 /data/DAZ%203D/Genesis%208/Female/Morphs/DAZ%203D/Body/FBMHeavy.dsf#FBMHeavy /data/DAZ%203D/Genesis%208/Female/Morphs/DAZ%203D/Body/FBMHeavy.dsf#FBMHeavy
    Baked morph (Genesis 8 Female.001): FBMHeavy = 1.000000
    buildBaked Genesis 8 Female 2 0
    buildBaked Genesis 8 Female 2 0
    buildBaked Genesis 8 Female 2 0
    buildBaked Genesis 8 Female 2 0
    ref: #CTRLArmsFrntBck {'output': 'Genesis8Female:/data/DAZ%203D/Genesis%208/Female/Morphs/DAZ%203D/Base%20Pose/pCTRLArmsFrntBckRight.dsf#pCTRLArmsFrntBckRight?value', 'operations': [{'op': 'push', 'url': 'Genesis8Female:#CTRLArmsFrntBck?value'}, {'op': 'push', 'val': 1}, {'op': 'mult'}]}
    

    each time it says “buildBaked” is a call to buildBaked, and I output the rig.name, len(bpy.context.scene.objects) and len(rig.DazBakedFiles).

    Is there a place in the code where the rig is re-created repeatedly? Maybe something that copies the properties of the rig but is missing DazBaked and DazBakedFiles?

  2. Rakete reporter

    So looking at DazLoader.loadDazFile, there is a Genesis 8 Female.001 in my scene, until the SkinBinding postbuild is processed:

    asset.postbuild <SkinBinding /data/DAZ%203D/Genesis%208/Female/Genesis8Female.dsf#SkinBinding> <GeoNode /Sync/Simple%20Test/Simple%20Test.duf#geometry 0 M:16 C: <Vector (0.0000, 0.0000, 0.0000)> R: <bpy_struct, Object("Genesis 8 Female.001") at 0x0000026994186B08>>
    asset.postbuild <Formula /data/DAZ%203D/Genesis%208/Female/Morphs/DAZ%203D/Base%20Pose/pCTRLArmsFrntBck.dsf#CTRLArmsFrntBck 0.000000> <FigureInstance Genesis8Female 0 P: None R: <bpy_struct, Object("Genesis 8 Female") at 0x0000026994186408>>
    

    the address also changes (from 0x0000026994186B08 to 0x0000026994186408). So I suspect somewhere in the SkinBinding postbuild the rig is re-created. I’ll check that out next.

  3. Rakete reporter

    Does the order in which these are processed actually matter? I guess an easy fix would be to just do the SkinBinding first, then all the other assets.

  4. Rakete reporter

    Alright, all of that about re-creating rigs was wrong. The mysterious Genesis 8 Female.001 with the different address is simply the mesh. Which is then renamed to Genesis 8 Female Mesh. So, with my changes the FBMHeavy property is actually created, but on the mesh! So if I do this:

    def buildBaked(self, context, inst):
      rig = inst.rna
      if rig.type != 'ARMATURE' and rig.parent is not None:
        rig = rig.parent
    

    at the top of buildBaked, then the property is actually created correctly on the rig.

  5. Thomas Larsson repo owner

    FBMHeavy is now listed among the baked morphs. However, while it is baked and should be listed for completeness, I don’t think it is so useful, since there are no custom morphs associated with it. So nothing happens when we press the Import Corrections button.

    Another thing that happens is that some eyelash morphs also appear in the list of baked morphs. It would seem more natural if they were associated with the eyelash armature, but that’s not how they are defined in DS.

  6. Rakete reporter

    The reason I was looking into that is because I am hoping to use these pre-baked properties when importing keyframes into an animation. When I create a figure with that heavy slider set to 50%, and then want to animate the slider to 100%, then applying a pose with the 100% slider to a pre-baked figure did not take into account that the figure already has the slider pre-baked at 50%. In effect applying something 100% which it should only have applied 100-50=50%.

    I actually have a hack in my repo that tries to correct this by using a property on the rig which contains a pose file with “corrections” (similar name to your corrections, but kind of different purpose). So that hack would look up a property in the “corrections” pose, then subtract whatever value is specified there from the applied value before applying it.

    See here: https://bitbucket.org/rakete/import_daz/src/d7c5a6b01cff8310ca0d58e2916ef9be7e3f3775/animation.py#lines-2437

    Though that hack is not very user friendly, so I was thinking it might be better to use those pre-baked sliders. Essentially I can change that code to look at pre-baked sliders and subtract their value before applying a pose, which should give me the same result.

    I also thought about adding an option to ImportPose so that a “zero pose file” can be specified. This would be the same as these “Corrections” files but with a better name. Because in principle what I am doing is correcting for the fact that the zero pose in Daz and Blender can be different because the diffeo export bakes everything into the figure.

  7. Rakete reporter

    @Alessandro Padovani I can only answer here. Because I have the same problem as @bouich jules (who I can’t @ actually). I can’t create new issues and I can’t answer in issues I have not created.

    I resolved it in https://bitbucket.org/Diffeomorphic/import_daz/issues/1181/i-cant-create-new-issues by posting the Bitbucket community support forum: https://community.atlassian.com/t5/Bitbucket-questions/I-can-t-create-any-issues/qaq-p/2305123

    Maybe it makes sense for you guys to report it to Bitbucket in that forum as well? They might care more if the project/admin owner complained. I can also make a ticket again, or add my voice to a ticket you created.

  8. Rakete reporter

    Editing posts also doesn’t work. It does feel like they want you to use Jira, and the free issue tracker just isn’t really getting much love from them.

  9. Thomas Larsson repo owner

    I very much doubt that Bitbucket will care more if I or Alessandro complained. After all, this is a small project with a single developer who is using Bitbucket for free. And it is difficult to say something when I don’t experience the problem myself.

    One thing that I have noticed is that I have to reload the page after I have logged in, otherwise I cannot make comments at all. But that is evidently not your problem.

  10. Thomas Larsson repo owner

    The issue tracker seems to accept new issues again. I just created one with my other identity, although I had to solve a recaptcha which I don’t recall that I had to do before.

  11. Log in to comment