Tuesday, June 30, 2020

Add-on scripting

Since the latest changes to the add-on names were made to allow scripting, it is time to present a little script that uses both the Daz importer and the BVH retargeter. The script imports a Daz character from a .duf file, merges the rigs, and retargets the first 200 frames of a BVH animation to the armature, all in one go. For performance reasons, the script also excludes all meshes from the scene before retargeting the BVH file, and finally puts them back again. This example shows why the Daz importer's addon mechanism is insufficient: a sub-addon can only access the Daz importer but not other add-ons like the BVH retargeter.

To run this script you need version 1.4.2 of the Daz importer and the development version (2.0.1) of the BVH retargeter. Not surprisingly, I encountered some problems when I first tried the script, which are fixed with the latest commit.

Here are lists of the operators defined by the add-ons:
https://diffeomorphic.blogspot.com/p/daz-operators.html
https://diffeomorphic.blogspot.com/p/mcp-operators.html
The add-ons also define some functions, but they have not yet been documented.

And here is the script:

import bpy
import os
import import_daz
import retarget_bvh

def check_import_error():
    # The error message is the empty string if everything ok
    msg = import_daz.getErrorMessage()
    if msg:
        print("Import error: \"%s\"" % msg)


def check_retarget_error():
    # The error message is the empty string if everything ok
    msg = retarget_bvh.getErrorMessage()
    if msg:
        print("Retarget error: \"%s\"" % msg)


def exclude_meshes_collection(flag, lcoll):
    if lcoll.name.endswith("Meshes"):
        lcoll.exclude = flag
    for lchild in lcoll.children:
        exclude_meshes_collection(flag, lchild)


def main():
    # Daz importer in silent mode
    import_daz.setSilentMode(True)

    # Import the file

    filepath = "~/Documents/DAZ 3D/Docs/anna.duf"
    filepath = os.path.expanduser(filepath)
    bpy.ops.daz.import_daz(

        filepath=filepath, 
        fitMeshes='UNIQUE')
    check_import_error()
    rig = bpy.context.object

    # Merge rigs

    bpy.ops.object.select_all(action='SELECT')
    bpy.ops.daz.merge_rigs()
    check_import_error()


    # Exclude meshes from scene for performance
    lcoll = bpy.context.view_layer.layer_collection
    exclude_meshes_collection(True, lcoll)

    # Restore Daz importer non-silent mode
    import_daz.setSilentMode(False)

    # BVH retargeter in silent mode
    retarget_bvh.setSilentMode(False)

    # Ensure that the BVH retargeter is initialized
       
    bpy.context.view_layer.objects.active = rig     
    retarget_bvh.ensureInited(bpy.context.scene)

    # Retarget BVH file to the active rig
    filepath = "C:/home/bvh/accad/Female/Female1_B03_Walk1.bvh"
    bpy.ops.mcp.load_and_retarget(
        filepath=filepath,
        startFrame=1,
        endFrame=200
        )
    check_retarget_error()

    # Restore BVH retargeter non-silent mode
    retarget_bvh.setSilentMode(False)

    # Include meshes in scene again
    exclude_meshes_collection(False, lcoll)


main()