Wednesday, June 25, 2025

Scanning the DAZ database is now obsolete

 I'm a Windows user myself, but the DAZ Importer still runs on Linux. The problem with Linux is that its file system is case sensitive, so e.g. Runtime/Textures and runtime/textures are different directories on Linux, whereas they are the same on Windows. To deal with these problem we previously had to scan the entire DAZ database, cf the post on Linux Revisited. Alas, this led to several problems. Scanning the database could take considerable time if many DAZ assets have been installed. Moreover, scanning is error prone because if you add new assets, they will not be found unless the database is rescanned.

Fortunately, these are now problems of the past. In the last commit, the relevant paths are scanned on the fly, meaning that a separate scanning step is obsolete. Having to look at several locations for an asset does have a price, but it seems to be a modest one. My initial tests indicate that importing files with "Case-Sensitive File Paths" enabled increases the load time with about 10%.

And please note that this is only an issue under Linux. Under Windows, and I believe Mac as well, file paths are case insensitive so the issue never arises.

Tuesday, May 20, 2025

Importing DBZ Files Directly

Getting the DAZ Importer up and running is a bit more complicated then using a normal importer. We must Copy Scripts folder to DAZ Studio, Save Scene in DAZ Studio, and Export To Blender. Those are the steps that any export script would need to do. But the DAZ Importer also required two extra steps, Save the DAZ root paths in DAZ Studio, and also Setting up the DAZ root paths in Blender. Those steps are necessary because the DAZ assets are not stored in the duf file. Instead the duf file contains pointers to the actual assets relative to the root paths. So knowing the root paths is necessary to find the assets.

However, the extra steps have been automated in the development version, which means that the DAZ Importer behaves more like a normal importer: export the dbz file from DAZ Studio and import it into Blender. The root paths are stored inside the dbz file, provided that you copy the latest version of the Export To Blender script a the DAZ Studio scripts folder. Older dbz files can also be imported, but in that case the root paths must be set up correctly first.

When we now press Easy Import DAZ or Import DAZ Manually, we notice two differences:

  • The file list contains dbz files instead of duf files and pictures.
  • The Mesh Fitting option is gone. 
The default root paths are probably not correct. Previously we had to set up the root paths manually, or export the root paths from DAZ Studio and load them into Blender. This is no longer necessary if we use the latest version of the Export To Blender script, because the root paths are now stored inside the dbz file. If we import an older dbz file it is still necessary to set up the correct root paths.

After the dbz file has been imported, the root paths are updated.

There are two new global settings that control the behaviour.

  • Only DBZ Files. If disabled the file selector looks like it used to, showing duf and dsf files and images. The Mesh Fitting option is also shown.
  • Root Paths From DBZ. If enabled the plugin uses the root paths in the dbz file, otherwise the root paths in the global settings are used.

Here is the file selector if DBZ Files Only is disabled. The file selector contains duf files and pictures. The Mesh Fitting options are shown.

Sunday, April 6, 2025

Diffeomorphic Add-ons Version 4.4.0 Released

Version 4.4.0 of the DAZ Importer, MHX Runtime System, and FBX and BVH Retargeter have been released. They can be downloaded from

The previous stable version 4.3.0 does not work with Blender 4.4 due to an API change.

Apart from working with Blender 4.4, there are also many bugfixes and some other changes.

Wednesday, March 19, 2025

Scripting Improvements

I have spent a log of time developing the DAZ Importer plugin, but I rarely use its scripting capabilities. However, every button becomes an operator that can be called from a script; a list of operators defined by the DAZ Importer can be found here. These operators are defined automatically and usually work out of the box, but there are some caveats regarding operators that act on multiple files, morphs or shapekeys.

Assume that we want to import a figure with Easy Import. We select the duf file (or the corresponding .png or .tip.png file) and press Easy Import DAZ. To do the same thing programatically, we could expect that the following script would work: 

bpy.ops.daz.easy_import_daz(
    filepath = "D:/home/scenes/victoria-rocker.duf"
)

However, nothing is imported. The reason is that the Easy Import tool can import several files at once. If we select the following three files, three different figures will be imported at once.

And here are the figures in Blender.
Importing multiple character in one stroke may not seem very useful, but we may want to import thirty different props from a single directory, and then it is easier to ímport thirty files at once than to press the Easy Import button thirty times and only import a single prop each time.

The old way to import multiple files uses the api.set_selection function, which needs to be called before easy_import_daz is invoked. Functions defined by the DAZ Importer plugin are documented here.

import bpy
from bl_ext.user_default.import_daz import api

api.set_selection([
    "D:/home/scenes/aiko-basic-wear.duf",
    "D:/home/scenes/victoria-rocker.duf",
    "D:/home/scenes/michael-basic-wear.duf"])
bpy.ops.daz.easy_import_daz()


Unfortunately, this does not work very well. Under the hood the set_selection function sets a global variable, and this leads to complications for operators that invoke other operators, like easy_import_daz does. Recently I learned from Rakete that there is another way to access multiple files which does not involve any global variables.

When a file selector exists, it sets two keyword arguments: the StringProperty "directory" and the CollectionProperty "files". An alternative way to import multiple files is like this:

bpy.ops.daz.easy_import_daz(
    directory = "D:/home/scenes",
    files = [{"name" : "aiko-basic-wear.duf"},
             {"name" : "victoria-rocker.duf"},
             {"name" : "michael-basic-wear.duf"}])


Actually, importing files in this way has always worked, but I was not aware of it. The "files" argument is a bit complicated; it is a list of dicts with the "name" keyword, which is how we specify a CollectionProperty in scripts.

To import a single file we simply let "files" be a list with a single argument.

bpy.ops.daz.easy_import_daz(
    directory = "D:/home/scenes",
    files = [{"name" : "victoria-rocker.duf"}])

    
This way of importing multiple files is not limited to Easy Import. The following script imports three poses to the active object. The second line turns on automatic keying.

import bpy
bpy.context.scene.tool_settings.use_keyframe_insert_auto = True
folder = "/people/genesis 8 female/poses/base poses/"
files = ["base pose kneeling a.duf",
         "base pose kneeling b.duf",
         "base pose kneeling c.duf"]         
bpy.ops.daz.import_pose(
   directory = api.get_absolute_path(folder),
   files = [{"name" : file} for file in files],
)


This script imports three poses to consequtive frames. 

Many tools opens another type of selector, which lets us select which morphs to import, which shapekeys to transfer, which materials to modify, etc. Such selections used to be made with the api.set_selection function as well, but now the preferred way is to use the "selection" keyword. Again the argument is a CollectionProperty, which corresponds to a list of dicts with the "name" keyword in scripts.

The following script import three units morphs:

files = ["eCTRLEyesClosed.dsf",
         "eCTRLEyesClosedL.dsf",
         "eCTRLEyesClosedR.dsf"]
bpy.ops.daz.import_units(
    selection = [{"name" : file} for file in files]
)

It is thus equivalent to the following selection in the Import Units dialog.

If the "selection" keywprd is omitted, or equivalently if selection = [], all elements are selected. Thus the line

bpy.ops.daz.import_visemes()

imports all available viseme morphs. We can then set the corresponding rig properties.

rig = bpy.context.object
rig["eCTRLvAA"] = 1.0
rig["eCTRLvOW"] = 0.4



Thursday, March 6, 2025

Mathjax Test

The formulas in the header.

\[\begin{align}
[{\cal L}_\xi, {\cal L}_\eta] &= {\cal L}_{[\xi,\eta]}
 + {1\over{2\pi i}}\int dt\ \dot q^\rho(t)
 \Big( c_1\ \partial_\rho\partial_\nu\xi^\mu(q(t))\ \partial_\mu \eta^\nu(q(t))\ +\\
& \qquad\qquad\qquad +\ c_2\ \partial_\rho \partial_\mu \xi^\mu(q(t))\ \partial_\nu \eta^\nu(q(t)) \Big),\\
[{\cal L}_\xi, q^\mu(t)] &= \xi^\mu(q(t)), \\
[q^\mu(t), q^\nu(t')] &= 0. 
\end{align}\]

If you use Firefox with NoScript, as I do, you need to whitelist jsdelivr.net and polyfill.io, otherwise only the uncompiled LaTex code will show up.

If anybody wonders, this is the Virasoro-like extension of the diffeomorphism algebra in multiple dimensions. e.g. on the \(d\)-dimensional torus. When \(d=1\), both terms proportional to \(c_1\) and \(c_2\) reduce to the ordinary Virasoro algebra on the circle, a piece of mathematics that is popular e.g. in string theory and statistical physics. By the way, I discovered the \(c_2\) term myself a long time ago, which is something that I am still proud of (\(c_1\) was discovered by Rao and Moody).

When I started this blog almost a decade ago I had planned to write about this and how it in my opinion fits into physics, hence the name of the blog. I never got around to do that, but that might change in the future.

 

Tuesday, February 25, 2025

Adding Extra Bones to Rigify

Some character have non-standard bones, e.g. a rigged hair. When we convert such a rig to Rigify, the rigified rig contains those bones, but they may be inconvenient to pose individually.
 
Here we have a figure with a rigged ponytail. The ponytail bones belong to the Custom collection.,
And here the rig has been converted to Rigify, with the hair bones still in the Custom collection. Posing each of hair bone individually can be done but is inconvenient.There are a few things that we can do to make it easier to pose the ponytail.
We can Add IK Goals. This tool is located in the Rigging > Chains panel which requires that the Rigging Tools feature is enabled.
Alternatively, we can Add Winders.

However, Rigify is a modular rigging system and we may want to use some of the Rigify types. Previously that has not been so easy to do. In principle we can first generate the metarig, then add the custom bones to it, and finally rigify the modified metarig. However, that requires further postprocessing because the vertex groups must be renamed. In the last version of the DAZ Importer there is a much simpler way. Just select a bone in the original DAZ rig and add a Rigify type to it.

Let us give the ponytail the control of a basic Rigify tail. Select the bone that we want to be the root of the tail, and assign a suitable Rigify type to it. Here we choose spines.basic_tail.
The Rigify Type panel contains various option for the bone chain. By default a basic tail can only bend along the X axis.
Once a bone has been assigned a Rigify type, it is added to the metarig together with its descendants. Any parent bones that are not part of the standard Rigify armature are also added.
Now the rigified armature has a ponytail with the extra control bones.
The entire ponytail can now be posed by rotating the target bone at the end of chain.