Wednesday, August 10, 2022

Import Expression and the Scanned Morph Database

Update August 26, 2022

There has been some improvements since this post was originally written. First of all, the name of the button has changed; it is now called Import Expression rather than Import Morph. This reflects the typical usage: you typically import an expression from a directory called Expressions, and a pose from a directory called Poses. However, both Import Pose and Import Expression can import both poses and expressions.

There are now two buttons in the Morphs section:

Scan Morph Database works as before, and the new Check Database For Updates checks if you have installed any new morphs since the last time the database was scanned.
We can either choose to check all characters, or the active mesh, or specify which databases we need to check.
We get a list of characters where new morphs have been installed since the last scan.
As mentioned above, the import tool has been renamed to Import Expressions
  • Affect Bones: If enabled, poses are imported as well as morphs. 
  • Clear Morphs
  • Use Scanned Database:
  • Check For Updates: Check if the database for the active character needs to be rescanned because new morphs have been installed. Can be disabled if you know that the database is up-to-date.
  • Load Missing Morphs
  • Category: Loaded custom morphs are put in this category. Defaults to Loaded.
  • Make All Bones Posable: If any loaded morphs has made bones driven.
  • Affect Geografts:
  • Auto Keying: Automatically insert keyframes at the current frame.
And the expression is loaded.


Original post:

Morphs lead to problems. On the one hand we want to load lots of them, so they are available when we need them. On the other hand we run into serious performance problems when many morphs are loaded. It takes a long time to load many morphs, and a character with many loaded morphs becomes very sluggish when we animate. Also the user interface lacks visual cues (how do the morphs BEF01, BEF02, etc look?), and in the end we had probably forgotten to load the morph we needed anyway.

Why there is a performance problem is not a mystery. All drivers have to be recalculated every time the viewport is updated, and there are a lot of drivers if many morphs are loaded. It can be avoided with the Disable Drivers button, but that can only be done while we pose the character, not when we tweak the morphs.

But it doesn't have to be that way. Many custom morphs are simply combinations of basic morphs, either the face units or the FACS morphs, so it should be enough to load those. In the latest development version we can do just that.

The first step is to scan the entire DAZ Studio database and store the morph information for later use. The button that does this is called Scan Morph Database and is located in the Setup > Morphs panel. Since scanning the database can take a lot of time, only files related to the active mesh are scanned by default.

However, if we disable Scan Active Mesh, we can specify which characters to scan.

Scanning the database can take a long time, but fortunately it only has to be done once. Or every time new morphs have been installed on your system. Take a cup of coffee while the computer works.

When the scanning process is completed we import morphs with the new Import Morph button in the Posing panel.

Select the expression in the file selector.

And the expression is loaded. Keyframes are created if Auto Keying is enabled.

Note that the expression is always loaded at 100%. There is no slider that we can adjust if we want to reduce the strength of the morph, but if we loaded the morph with Auto Keying enabled we can achieve similar results by scaling the F-curves.

Since there now is a separate tool for loading morphs, the Load Pose tool no longer affects morphs by default. Instead we load poses and expressions in two separate steps. This is normally not a big deal since they are usually defined in separate files anyway.

And here is a combination of a pose and an expression.

Monday, August 8, 2022

Changes to the MHX rig

Recently there were some changes to how the MHX rig is controlled. 

  • Previously it was controlled by a mix of RNA and id properties (the difference is explained in more detail below), now only (API defined) RNA properties are used. Whereas you could argue which is the best choice, mixing the two types of properties was very confusing, e.g. because they are animated separately.
  • Previously MHX used armature properties, now it uses object properties. In order to use armature properties in a linked file, they had to be made both library overridable and library editable, whereas object properties only need to be library overridable. And armature RNA properties could not be keyframed at all.
  • Stretchiness is now controlled by the floating point influence rather than the boolean enable, to make animation smoother. Other control may be converted into float properties in the future for the same reason.

This may sound technical, but the changes should not alter the panels and the behaviour very much, at least after engetudouiti pointed out all the bugs that I introduced in the process. It means that MHX rigs generated with previous versions do not work. However, they can be updated to the latest version with the Update MHX button that appears in all MHX panels. Note that the update is irreversible, so if you have a scene that works with a previous version of the MHX RTS it might be better to stick to that. Another possibility, which I favour myself, is to keep a file with the original genesis character around, and regenerate the MHX rig from scratch.

RNA and id properties

An RNA property is defined by the python script when is loaded, and it is available for all data of a given type. An id property is defined dynamically at runtime, and is only defined for a single datum. An example of id properties are the morphs, which are loaded at runtime. Different characters can have different sets of morphs, although they are all armature objects. Hence morphs must be id properties.

Let us compare how the two types are accessed in Python. First RNA properties. They are defined by a statement like this (the last line makes the property accessible in a linked file).

bpy.types.Object.RNA_property = bpy.props.FloatProperty(
    name = "RNA Property",
    description = "RNA Property",
    default = 0.0,

To access an RNA property, we use getattr, setattr, or the dot notation, e.g.

    setattr(ob, "RNA_property", 0.5)
    ob.RNA_property = 0.5

Id properties don't have to be defined at all, they are just assigned and then they exist.

    ob["id_property"] = 1.0
A limitation with id properties is that they can only be floats, integers, or strings, but not booleans, enums, vectors, or collections. So instead of a boolean, we could use an integer property limited to the range [0,1]. This works in principle, but an integer is displayed as a slider rather than a checkbox. Since that is ugly, the old MHX RTS displayed the RNA property (a true boolean) rather than the id property (an integer).

But then came the next problem. Armature RNA properties don't seem to be animatable. So if you right-clicked on a float property like Gaze Follows Head (an id property since a float is natually displayed as a slider), you could set a keyframe, but if you right-clicked on a boolean property like Left Arm Stretch (an RNA property), keyframing was not available.

OK, so this was confusing? The bottom line is that by consistently using object RNA properties, all problems went away. Properties are animatable, booleans display as checkboxes, and everything works with file linking. At least after all bugs have been ironed out.