Saturday, July 25, 2020
New Morph System
However, this system had a few drawbacks. Once one starts to delete and edit morphs, the plugin could become confused. In particular, it could add multiple prefixes, like DzUDzC to the morph names. It was also not obvious what the original morph name was, since the beginning of the Daz name had disappeared. To overcome such drawbacks, a new morph system has been introduced. In the new system, the original Daz names is kept. To keep track of the morph type (Units, Expressions, JCMs, etc.), all morph names are stored in different collection properties, together with the user-friendly print name.
The change should be almost invisible for the user, except that the new morph system has introduced some bugs that need to be fixed. However, there are a few places where you can actually see the difference.
Shapekeys keep their original Daz names. In previous versions, the two last shapekeys would be called DzMAiko8Afraid and DzMAiko8Angry.
If an old file with a Daz character is opened, the Morphs panel consists of a single button. Once we press Update Morphs For Version 1.5, all objects in the scene are updated and the Morphs panel look as it did before.
It is not necessary to do the update when a new scene is imported with the Import DAZ button.
To access the morphs of a certain type from python, use the function import_daz.getMorphs(object, type). The function returns a dict which describes the morph.
The follow script prints all custom morphs of the active object
import bpy
import import_daz
ob = bpy.context.object
morphs = import_daz.getMorphs(ob, "Custom")
print("Keys")
print(morphs.keys())
print("Values")
for item in morphs.values():
print(" %20s %20s" % (item.name, item.text))
Here is the output
Keys
dict_keys(['FHMAiko8', 'eJCMAiko8Afraid', 'eCTRLAfraid', 'eJCMAiko8Angry', 'eCTRLAngry'])
Values
FHMAiko8 FHMAiko8
eJCMAiko8Afraid Aiko8Afraid
eCTRLAfraid Afraid
eJCMAiko8Angry Aiko8Angry
eCTRLAngry Angry
If we load four expressions, we can print them by changing "Custom" to "Expression" in the script above, viz. import_daz.getMorphs(ob, "Expression").
Keys
dict_keys(['eCTRLAfraid', 'eCTRLAngry', 'eCTRLBereft', 'eCTRLBored'])
Values
eCTRLAfraid Afraid
eCTRLAngry Angry
eCTRLBereft Bereft
eCTRLBored Bored
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()
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.