Wednesday, July 15, 2020

More on scripting

Updated October 10, 2021: There are some changes in the scripting interface in version 1.6.0 of the DAZ Importer. See Scripting for version 1.6 for details.


Updated July 15, 2020: setFilePaths replaced by setSelection. Added code for transferring and removing morphs.


Recently we discussed how to import a Daz scene and merge rigs from Python, but we did not attempt to import morphs to the new character. Afterwards I realized that doing so does not work at all. The problem is that the operators which import multiple files use a collection property, and specifying collection properties from Python seems impossible. At least I did not figure out how to do it.

Instead the problem is solved in a different way in the development version: with a global variable. Whenever the UI creates a file selector that generates multiple inputs, we need to call the function

import_daz.setSelection(list_of_filepaths)

before calling the operator. This function sets the global variable from which the filepaths are taken.

So let us write a script that imports various things from Python. We start by importing the relevant modules and settings up the root path. 

import os
import bpy
import import_daz
rootpath = os.path.expanduser("~/Documents/DAZ 3D/Studio/My Library")


With the character rig or mesh active, we next import three morphs that close the eyes

headpath = "/data/DAZ 3D/Genesis 8/Female/Morphs/DAZ 3D/Base Pose Head/"
folder = rootpath + headpath
files = ["eCTRLEyesClosed.dsf", "eCTRLEyesClosedL.dsf", "eCTRLEyesClosedR.dsf"]
paths = [folder+file for file in files]
import_daz.
setSelection(paths)
bpy.ops.daz.import_units()

If we have invoked the operator with the 'INVOKE_DEFAULT' argument, it would instead have launced a morph selector in the same way as the Import Units button does.

bpy.ops.daz.import_units('INVOKE_DEFAULT')

Next we import two custom morph

yoyopath = "/data/DAZ 3D/Genesis 8/Female/Morphs/Hamster/YOYO/"
folder = rootpath + yoyopath
files = ["FBMYoyo.dsf", "FHMYoyo.dsf"]
paths = [folder+file for file in files]
import_daz.
setSelection(paths)
bpy.ops.daz.import_custom_morphs()


Note how the eyes have moved relative to the eyelashes. Loading morphs can be of limited use since Blender shapekeys only affect the mesh, whereas Daz morphs can affect the rig rest pose as well. To fix this we transfer the two Yoyo morphs to the eyelashes.

ob = bpy.data.objects["Genesis 8 Female Eyelashes"]
ob.select_set(True)
import_daz.setSelection(["DzMFBMYOYO", "DzMFHMYOYO"])
bpy.ops.daz.transfer_other_morphs(useDriver=True)

Then we import some standard JCMs

jcmpath = "/data/DAZ 3D/Genesis 8/Female/Morphs/DAZ 3D/Base Correctives/"
folder = rootpath + jcmpath
files = ["pJCMAbdomen2Fwd_40.dsf", "pJCMAbdomenFwd_35.dsf"]
paths = [folder+file for file in files]
import_daz.
setSelection(paths)
bpy.ops.daz.import_standard_jcms()

This technique is not limited to importing morphs. The next code snippet resizes all textures that involve the arms. At this point the active object must be the character mesh, the blend file must be saved, and we must have saved local textures. Otherwise the operator will fail with a polling error.

folder = "/home/myblends/characters/test/textures"
paths = []
for file in os.listdir(folder):
    if "Arms" in file:
        paths.append(os.path.join(folder, file))
import_daz.
setSelection(paths)
bpy.ops.daz.resize_textures(steps=3)


Finally we change the active object to the armature, and load the first three poses in the Base Poses directory.

posepath = "/People/Genesis 8 Female/Poses/Base Poses/"
folder = rootpath + posepath
paths = []
for file in os.listdir(folder):
    if os.path.splitext(file)[-1] == ".duf":
        paths.append(folder+file)
import_daz.
setSelection(paths[0:3])
bpy.ops.daz.import_action()

Finally we remove the eyes closed morphs again.

rig = bpy.context.object
keys = [key for key in rig.keys() if "Closed" in key]
import_daz.setSelection(keys)
bpy.ops.daz.remove_standard_morphs()

The eyes closed morphs are removed but the eyes squint morphs remain.

An updated list of operators can be found at https://diffeomorphic.blogspot.com/p/daz-operators.html. It specifies the operators that use import_daz.setSelection to get its arguments.