Cascadeur Python API

Python scripting in Cascadeur provides low-level access to the software systems.
However, at the moment its coverage is somewhat uneven. Available methods focus mainly on rig generation and rigging tool implementation, while other areas are paid less attention.

There are approximately 20 000 lines of code, mostly they implement rig generation and rigging tool implementation.

API Architecture

Python API in Cascadeur provides two main points of access to the scene:

First, there is Cascadeur application level (sometimes referred to as Presenter for historical reasons).
It is accessible mainly via csc.app.Application (to get an instance use csc.app.get_application()).

You can work with several submodules on this level:

Application
https://cascadeur.com/python-api/_generate/csc.app.Application.html
Used for accessing the scene itself and managers associated with it (tool manages, scene settings and such).

Tools Manager
https://cascadeur.com/python-api/_generate/csc.app.ToolsManager.html
Used for accessing Animation Tools based on their names, and for performing various operations with these tools.

View
The part that handles scene visualization and the user input. View has direct access to the Domain and its data, but never makes any changes to this data.

Fbx
Used for working with files in .fbx format.

Cascadeur application has a set of components and uploads a number of tools using a common interface.
On the application level you can call dialogs, work with scenes as tabs, access scene settings etc.
Examples of working with this part of the API can be found in the resources/scripts/python/commands/rig_additional/ra_samples/regen_rigs.py script.

Second, there is the lower level. It should be used when you need to read and modify the structure of the model, animation data, data associated with Animation Tracks on the Timeline (these tracks are called Layers in the API) etc.
It can be interacted with through the Scene class:
https://cascadeur.com/python-api/_generate/csc.domain.Scene.html

You can work with submodules domain, model, update, layers via this level.

Domain is the ‘main’ part of the software. It is independent from the user input, and from the way said input is handled.

API Interfaces

Domain, in turn, includes several interfaces for working with various aspects of the scene:

Update
https://cascadeur.com/python-api/_generate/csc.update.Update.html
Also known as the Node Editor, only accessible when editing. If you only need to read data values, use Data Editor instead.

Behavior Editor
https://cascadeur.com/python-api/_generate/csc.model.BehaviourEditor.html
Used to work with Behaviors.

Model Editor
https://cascadeur.com/python-api/_generate/csc.model.ModelEditor.html
Used to work with objects; also serves as an interface for other editors.

Layers Editor
https://cascadeur.com/python-api/_generate/csc.layers.Editor.html
Used for working with Animation Tracks; has its own Modify method specifically for this purpose.

Note

In the Python API, Animation Tracks are referred to as Layers. This is a leftover from the time when Layers were their official title.

import csc

# find track body, remove key on frame 11
# change interpolation on interval for key on frame 0 to BEZIER and GR


def test(model, update, scene):
    lv = scene.layers_viewer()
    le = model.layers_editor()

    for lid in lv.all_layer_ids():
        layer_header = lv.header(lid)
        if layer_header.name == "Body":
            le.unset_section(11, lid)

            def mod_section(section):
                section.interval.interpolation = \
                    csc.layers.layer.Interpolation.BEZIER
                section.interval.common.ik_fk = csc.layers.layer.IkFk.GR

            le.change_section(0, lid, mod_section)

scene.modify('test', test)


Asset Manager
https://cascadeur.com/python-api/_generate/csc.domain.assets.AssetsManager.html
This one is used for working with mesh data. Examples of using it can be found in the resources/scripts/python/commands/print_mesh_info.py script file.

Using API

Reading data from the scene can be performed by directly accessing the Viewers.

If you need to edit the data, there are a number of modify methods for changing the domain scene. These methods take a number of parameters to make changes to the scene.

Note

Modify methods also save the scene history (the same one used by Undo and Redo functions). This is why the API looks the way it does.

For an example of using these methods, see the resources/scripts/python/samples/move_joints.py script, where they are used for moving joints.

Modify Methods

Modify methods are the main tool for making changes to Cascadeur scenes.

There are several such methods in Cascadeur API. The difference between them is whether they do or don’t allow you to access the session and scene_updater.
The session is an interface that provides access to the API on a level higher than interfaces like the model, update editor, animation and such: for example, it can be used to work with AutoPosing controllers.
Here is an example of using session in the add_locator.py script:

def mod(model, update, sc, session):    

    obj_id = csc.parts.Buffer.get().insert_object_by_path('objects/locator.casc',

update.root().group_id(), model,

sc.assets_manager())
    if scene.model_viewer().get_object_name(obj_id) == 'Locator':
        model.set_object_name(obj_id, c_mh.increment_object_name(scene, 'Locator'))
        session.take_selector().select({obj_id}, obj_id)

scene.modify_with_session(command_name(), mod)
 


Scene_updater, on the other hand, is a system that allows you to run the update mechanism. For example, it can be used to calculate global datas (parameters) on the basis of local ones, or positions of Point Controllers based on Joint positions, or vice versa.
This is done by calling this command:

scene_updater.run_update(actuals, frame)

Here, actuals is a set of data ids that will be used to update the system. E.g. if you’d like to use local Joint positions and rotation values, you should put IDs of these joints to the set; once the function is called, global parameters for Joints, Point Controllers, Boxes etc. will be updated.

For the scene to work correctly, you should also run the scene_updater.generate_update() command every time you make any alterations to the scene topology (structure), so it would be modified in accordance with the changes you’ve made.

Here is the logic:

  • Right after modify interpolation will be executed. If scene_updater is in invalid state, the program will crash.
  • If you use modify without access to scene_updater, then scene_updater will call generate_update right after your modify function is executed (it happens automatically).
  • If you have access to it, you have to call it manually. This is done so that generate_update is not called twice.
  • All this allows you, if needed, make any changes to topology, update any data and make changes again etc. But you have to be careful not to call run_update between changing topology and running generate_update.
  • If you don't change topology, you don't need to run generate_update at all.

Some examples of using scene_update can be found in the following scripts.
The first is move_joints.py (used only to update the scene, without changing the topology):

def move_joints(scene):
    mv = scene.model_viewer()
    dv = mv.data_viewer()
    bv = mv.behaviour_viewer()

    joints = bv.get_behaviours('Joint')

    def mod(model_editor, update_editor, scene_updater):
        de = model_editor.data_editor()
        positions = set()

        for bh_joint_id in joints:
            bh_owner_id = bv.get_behaviour_owner(bh_joint_id)
            tr_bh_id = bv.get_behaviour_by_name(bh_owner_id, 'Transform')
            pos_id = bv.get_behaviour_data(tr_bh_id, 'global_position')
            global_position = dv.get_data_value(pos_id, 0)
            positions.add(pos_id)
            de.set_data_value(pos_id, 0, global_position + [1.0, 1.0, 1.0])

        scene_updater.run_update(positions, 0)

    scene.modify_update("Move joints' positions", mod)


Another is delete_objects.py:

def delete_rig_infos(scene, sel_rig_infos, independent_objects):
    mv = scene.model_viewer()
    bv = mv.behaviour_viewer()

    def mod(model, update, scene_updater):
        cm_ri_rm.delete_rig_infos(scene, sel_rig_infos, model, bv)
        model.delete_objects(independent_objects)
        frame_no = scene.get_current_frame()
        scene_updater.generate_update()
        scene_updater.run_update(set(), frame_no)

    scene.modify_update(command_name(), mod)

 

See Also

Python Scripting in Cascadeur

Cascadeur Architecture

Was this article useful to you?

0
0