Scripting Hell (Morphs and Transferring Shape Keys)

Issue #2186 closed
Midnight Arrow created an issue

After looking over the sample script for loading morphs, it shows clearly that a user needs to create a list of morph names, pass it to import_daz.set_selection(), and then call bpy.ops.daz.transfer_shapekeys() (which presumably operates on the selection). But it’s not clear what is the correct (from a public API standpoint) way to generate a list of morphs already loaded on the figure, like those in the invoke menu. From a cursory look at the API, it seems like import_daz.get_morphs() is what I’m looking for. But it doesn’t work the way the docs say it does. It says it accepts either a mesh or an armature, but whenever I try and use it on a mesh the dictionary it returns is empty.

Steps to reproduce:

  1. Load a (G8F) figure
  2. Load JCMs and FACS
  3. With the figure mesh selected, run the following commands in the Python console:
import import_daz
print(import_daz.get_morphs(bpy.context.active_object, 'All'))

Even though it specifies ‘All’, nothing is returned. If we run the command again with the armature selected, we do get some morphs returned. But only the FACS and the baked morphs. The JCMs are totally absent. Even though the function has a parameter to return JCMs, it seems like it only returns the front-facing morphs that are displayed in the runtime panel.

So after I couldn’t get get_morphs() to work, I inspected the mesh and discovered the DazMorphUrls property, which seemed promising. But even though I successfully got the list of JCMs from it and managed to filter out the ‘Body’ morphs, bpy.ops.daz.transfer_shapekeys() kept failing. After over an hour of futile attempts to get it to work, I discovered the problem is actually that Daz3D mislabeled their files. The morph named “pJCMChestLeft_20_L.dsf” actually has an ID of “pJCMChestLeft_24_L” in the file. The shape key is named one thing, but the name in DazMorphUrls is another. So bpy.ops.transfer_shapekeys() complained because it was expecting “pJCMChestLeft_24_L”, but it got “pJCMChestLeft_20_L” instead.

At this point, I just gave up and imported classifyShapekeys() straight out of selector.py, which is what the operator calls when it is invoked. It works fine, but since it’s not part of the public API, I’m concerned that Thomas will change it thinking nobody else uses it, and totally break my scripts.

I’m not sure what’s a bug here and what’s a design decision that I don’t get.

I’m using Blender 4.2.1 and Diffeomorphic 4.2.0-stable.

Comments (7)

  1. Alessandro Padovani

    Personally I never dealt with the daz api, and I only use a little blender api for some quick rigging tools so my experience is limited. But if it can help, I understand in daz studio there’s the url for files, then the id which should be unique but sometime it isn’t due to PA errors and in this case daz studio reports duplicates in the daz log, plus there’s labels which are displayed in the interface. Then there’s aliases to duplicate properties in various categories mainly for the user interface, which ideally could be avoided if we don’t want to replicate the daz interface categories.

    The hell with daz morphs is they drive each other, making them broken even in daz studio itself. See #2158.

  2. Midnight Arrow reporter

    Yes, the DSON specs have both an “id” and a “name”. The ID property seems like the thing that really matters. I tinkered with a script to load a G8 armature, and it kept failing until I realized that the bone with the name “abdomenUpper” actually has an ID of “abdomen2”, which is what the parenting looks for. There’s also other weird things. The ID for the bone lCarpal2 has “-1” after it for no reason other than poor QA at Daz (but what else is new?).

    Then there’s the URL, which is used for identifying assets in files Luckily Python’s pathlib and urllib work great for dealing with them. A few days ago, I wrote a custom script to parse the character folders, figure out which morphs are driven by the URL pointing to “ECTRLEyesClosedL/R”, and procedurally hook the G8 eyelid morphs up to the FACS Eye Blink control.

    Regarding #2158: I don’t think that’s “broken”, per se. If you examine the “Eyes Closed Left” morph in the properties menu, it says the Raw value is -100%. That’s what you’d expect to see. The only real problem is a Daz Studio UI issue. It would ideally have a way of informing the user that the raw value is lower than the clamped value.

  3. Thomas Larsson repo owner

    Alternative bone names, such as “abdomenUpper”/”abdomen2”, are read from the duf file and stored in the “DazBoneMap” armature property.

  4. Midnight Arrow reporter

    I was trying my hand at loading assets from scratch, without using Diffeomorphic. So I didn’t have the DazBoneMap property available. It certainly made me appreciate how much work goes into getting around Daz’s shitty QA.

  5. Log in to comment