- edited description
How do you load a subset of the standard JCMs from script in 1.4.2?
Is it possible to load a subset of the standard JCMs from a script while bypassing the selection dialogue?
I’ve tried calling bpy.ops.daz.import_standard_jcms but I can’t get that to work. The problem appears to be that certain properties must be set which only get set by invoke() and invoke() isn’t called when you call the operator from a script, unless you do import_standard_jcms("INVOKE_DEFAULT"), but that just opens the selection dialogue.
Something like this seems to work:
from import_daz.morphing import LoadMorph
loader = LoadMorph(mesh=mesh, rig=rig)
loader.type = "Correctives"
loader.prefix = "DzC"
loader.useShapekeysOnly = True
loader.useSoftLimits = False
loader.usePropDrivers = False
loader.useBoneDrivers = True
loader.useStages = True
paths = {'Abdomen2Fwd_40': 'path\\to\\pJCMAbdomen2Fwd_40.dsf'}
loader.getAllMorphs(paths, bpy.context)
But is there a better way?
This same issue might also apply to loading other types of “morphs” but I haven’t tested that yet. In a previous version of the addon I was able to select which morphs I wanted to load by setting properties on the scene. For instance, for facial units:
FACIAL_UNITS = [
"DazMouthOpen",
"DazEyesClosedL",
"DazEyesClosedR"
]
# Deselect all units
bpy.ops.daz.select_all_morphs(type="Units", value=False)
# Select just the units we want
for u in FACIAL_UNITS:
setattr(bpy.context.scene, u, True)
# Load selected units
bpy.ops.daz.load_all_units()
But that doesn’t appear to work anymore. What’s the best way to do this sort of thing?
Comments (12)
-
reporter -
reporter - edited description
-
reporter - edited description
-
reporter - edited description
-
repo owner I don’t have a good answer to this yet. It should be something like this
from import_daz.utils import B
selection = []
for file in files:
item = B.DazSelectGroup
item.name = file
item.text = file
item.select = True
selection.append(item)
bpy.ops.daz.import_units(selection = selection, filter = "")
where DazSelectGroup is defined in buttons28.py. But it doesn’t work because I get the following error message.
TypeError: Converting py args to operator properties: DAZ_OT_import_units.selection expected a each sequence member to be a dict for an RNA collection, not RNAMetaPropGroup
-
repo owner Now I have at least been able to import custom morphs. However, it was necessary to make a change to the code so you need to use the development version. Also, it only seems possible to import one morph at a time, which means that some morphs will not load correctly (if they are defined in terms of other morphs, in the other morph file).
So you can do something like this:
bpy.ops.daz.import_custom_morphs(filepath = folder + "eCTRLEyesClosed.dsf", catname = "Unit")
bpy.ops.daz.import_custom_morphs(filepath = folder + "eCTRLEyesClosedL.dsf", catname = "Unit")
bpy.ops.daz.import_custom_morphs(filepath = folder + "eCTRLEyesClosedR.dsf", catname = "Unit")
-
reporter Ah, thanks for the clarification. At least I now understand how it was intended to work.
You were getting that error in your first example because “selection” is a CollectionProperty of PropertyGroups and must be passed as a list of dicts. Theoretically, something like this should work:
selection = [] item = {} item["name"] = "path\\to\\eCTRLMouthOpen.dsf" item["text"] = "MouthOpen" item["category"] = "" item["index"] = 0 item["select"] = True selection.append(item) bpy.ops.daz.import_units(selection=selection, filter="")
Except that doesn’t actually work. Instead you get this:
AttributeError: 'DAZ_OT_ImportUnits' object has no attribute 'char'
Which is pretty much the same problem you had to fix to make import_custom_morphs() work. The problem in this case is that “char” gets set only when StandardMorphSelector.invoke() is called, but invoke() doesn’t get called when you call import_units() from a script.
Anyway, thanks again for the help. I’m glad to know that I wasn’t overlooking something obvious when trying to get this to work.
-
repo owner I don’t understand how to change collection properties from python, but I think I found a nice way to load standard morphs (face units, visemes, standard jcms, etc). Use the new function import_daz.setFilePaths to specify the list of file paths before calling the operator. Here is an example:
import os
import bpy
import import_daz
rootpath = os.path.expanduser("~/Documents/DAZ 3D/Studio/My Library")
# Import some face units
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.setFilePaths(paths)
bpy.ops.daz.import_units()
# Visemes in same folder
bpy.ops.daz.import_visemes()
files = ["eCTRLvAA.dsf", "eCTRLvEE.dsf", "eCTRLvF.dsf"]
paths = [folder+file for file in files]
import_daz.setFilePaths(paths)
bpy.ops.daz.import_visemes()
# Import some 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.setFilePaths(paths)
bpy.ops.daz.import_standard_jcms()
-
reporter I don’t understand how to change collection properties from python…
Are you talking about doing something like this?
import bpy from import_daz.utils import B bpy.types.Scene.my_collection = bpy.props.CollectionProperty(type=B.DazSelectGroup) item = bpy.context.scene.my_collection.add() item.name = "path\\to\\eCTRLMouthOpen.dsf" item.text = "MouthOpen" item.category = "" item.index = 0 item.select = True # This is incorrect! bpy.ops.daz.import_units(selection=bpy.context.scene.my_collection, filter="")
You’d think that would work, but apparently it doesn’t. Instead, you need to pass a list of dicts for “selection” like in my earlier example. That list will get converted into a collection of DazSelectGroup items behind-the-scenes.
I’m really glad to see you’re making changes to make this possible/easier. I’ll check them out.
Anyway, thanks for your attention to this matter, and thanks for your continued work on this add-on! It really has made my life much easier. It’s also the first thing I recommend to people wanting to move from Daz to Blender.
If the reasons aren’t already obvious, it’s really important to me that all the functionality be accessible from script, so I can automate my pipeline as much as possible. So, for instance, if I need to add a morph, I just add it to the script and rebuild the figure without having to do anything by hand, which can be quite tedious and error-prone.
-
repo owner Here is the long answer: https://diffeomorphic.blogspot.com/2020/07/more-on-scripting.html.
Update: We can now use the same technique to transfer and remove morphs with a script. Some things, like removing categories, can still not be done from a script. Let’s see if I have the energy to fix that.
-
repo owner Here is something which works on with the latest version
import bpy
import import_daz
FACIAL_UNITS = [
"eCTRLMouthOpen.dsf",
"eCTRLEyesClosedL.dsf",
"eCTRLEyesClosedR.dsf"
]
# Absolute root path on my computer.
root = "D:/DAZ 3D/Studio/My Library/"
# Relative path to the folder where the poses are located
folder = "/data/DAZ 3D/Genesis 8/Female/Morphs/DAZ 3D/Base Pose Head/"
# Absolute paths to the files
paths = [root+folder+unit for unit in FACIAL_UNITS]
# Set selection
import_daz.setSelection(paths)
# Load selected units
bpy.ops.daz.import_units()
-
repo owner - changed status to closed
I think this is working now.
- Log in to comment