While SALSA Suite v2 has a rich Editor (design-time) setup environment, all functionality can be implemented at runtime as well. Due to the myriad available settings options and configuration details, full runtime setup is involved. Most of the information in this document can be found elsewhere within the Suite documentation; however, this article aims to consolidate the workflow basics and refer to the details available elsewhere.

General Workflow

All modules in the Suite (SALSA, EmoteR, and Eyes) follow these general rules:

  1. Setup the model character settings and Expression(s) with ExpressionComponent(s).
  2. Bake the configuration data into serialized controller data.

See the API configuration examples for SALSA, EmoteR, and Eyes. Focus particularly on the last few lines for examples of how and when to perform the data baking.

NOTE: Both SALSA and EmoteR share identical configuration baking methods, while Eyes has some additional requirements. This is due to the sub-modules within the Eyes master-module. Since each sub-module (i.e. Heads, Eyes, Blink, etc.) can be exclusively enabled or disabled, they are broken out in the baking process. Additionally, there is a requirement to run the Initialize() method to create the guide objects Eyes uses to orient eye and head tracking.

Much of the expression and expression component configuration details are not available at runtime and will generate errors unless they are baked into the controllers. This is the unfortunate side-effect of Unity serialization with derived Types and trying to provide access to configure these Types in the Inspector. Nonetheless, we have tried to make this as easy as possible. If you are only working in design-time, this is a requirement you don't need to worry about. The Suite handles this for you when the project runs. However, at runtime, you do need to ensure this is part of your flow.

Implementing the Workflow

As mentioned above, there are two main/recommended steps in a runtime workflow -- 1) configure the model and 2) bake the controller data. Due to the detail required for implementing character configuration at runtime, it is highly recommended to simply examine the API configuration examples (SALSA example, EmoteR example, and Eyes example).

NOTE: New examples are added as the need arises and other examples, in addition to the above, may be available.

That being said, you may be wondering if it is possible to utilize a OneClick script to implement runtime configuration. The answer is YES. However, please note, this will configure your supported character, but the configuration data still needs to be baked into the underlying controllers. We recommend implementing the serialized controller helper data in addition to the runtime data set to ensure design-time needs are met as well. This is the method used by OneClicks.

Step 1: Configure the Model

Generally speaking, it is recommended to add SALSA Suite modules at runtime and not at design-time. The reason for this is the Inspector integration at design-time. Inspector code expects a valid configuration and assumes a design-time implementation. As such, many variables and settings are configured by the Inspector that prevent operation and errors when a misconfigured Suite module is run. It is possible to add modules without configuring them in design-time and perform configuration at run-time, it simply requires extra steps.

If it is desirable to add modules at design-time and configure them at run-time, it is recommended to minimally configure the modules to a run-worth state and then perform the reconfiguration at run-time. This will ensure the Inspector sets the module up for correct operation prior to running the scene.

Using a OneClick for Runtime Configuration

It is relatively easy to leverage a set of OneClick scripts to configure your character model at runtime. Please refer to the OneClick documentation for more information on OneClicks. The OneClick scripts use an Editor script to call configuration scripts on a pre-selected Hierarchy GameObject (usually the root of the character model's hierarchy structure). You can see these calls at the bottom of any of our available OneClick packages. Bear in mind, you may also need to unpack your character if it is a prefab and you are using Unity 2018.3+. You can see an example of how to do this in the OneClick Editor script.

When you are ready to configure your character, you will need to call each of the associated OneClick runtime configuration scripts. The following will use the Reallusion CC3 scripts as an example. Be sure to bake the data after running the configuration setup.

// configuration using v2.7.2+ OneClick and OneClickBase

GameObject gameObj; // usually the character root object in the hierarchy.

// add QueueProcessor required in v2.7.2+

// configure AudioSource required in v2.7.2+
var clip = AssetDatabase.LoadAssetAtPath<AudioClip>(OneClickBase.RESOURCE_CLIP);
OneClickBase.ConfigureSalsaAudioSource(gameObj, clip, true);

NOTE: While the AudioClip configuration may not be necessary for your project's runtime configuration, it is included here for consistency and completeness. However, you can ignore it here and configure your AudioSource.clip elsewhere if you wish.

Creating Your Own Custom Runtime Implementation

Utilizing the OneClick implementation strategy is highly recommended and a great source of example code. However, by design, current OneClicks only utilize shape and bone animation controllers and you may need to create your own runtime implementation for other controller types. It is not difficult, but does require understanding of the underlying data.

Although it is not required, it is recommended to examine an official OneClick to see how the data is serialized into a configuration. Keep in mind, a OneClick implementation is only one way to configure a character model. It may, or may not meet your needs. The SALSA documentation section also has a couple of runtime configuration examples.

The following section links to details on how this data is used and implemented for all controller types.

Making Sense of Configuration Data

Please refer to this page for detail on configuration data: Runtime Configuration Data Explained

The SALSA Suite of components has quite a bit of configuration data for all of the options which make it so flexible. As mentioned earlier, due to the backend data structures making the animation controllers a modular implementation, it makes serialization of the data quite difficult (or impossible) within the Unity engine. Allowing for Editor configuration requires quite a bit of serialization. Therefore, we have a separate set of data the Custom Inspector uses to hold the data until runtime. At runtime, the data is baked into the ExpressionController structures.

The configuration data is maintained in two data types: the ExpressionController (partially serialized) and the ExpressionControllerHelperData (fully serialized). When configuring a character at runtime, some understanding of these two classes is necessary to correctly configure a character model with the SALSA Suite. For easier reference, we have broken this information out into its own documentation page.

Please refer to this page for detail on configuration data: Runtime Configuration Data Explained

Step 2: Baking Controller Data

"Baking" the controller data is the process of converting and transferring the fully serialized data to the runtime controller structure. As mentioned elsewhere in this document, this process is required to provide a means of serializing the Inspector configuration and then applying that configuration to the modular and inherited structures used at runtime.

To bake the data, all modules essentially operate the same way. There are; however, a couple of small nuances to EmoteR and to Eyes that are different from SALSA. SALSA and EmoteR are very similar, so lets examine them first.

SALSA and EmoteR Requirements

Once the character model is configured (for runtime configuration, refer to the API and the API Configuration Example), the controller data needs to be updated. At design-time, this occurs in the Awake() game loop cycle. In order to implement it at runtime, call module initialization for SALSA. Leverage the API to perform this function.

CrazyMinnow.SALSA.Salsa salsaInstance; // reference to Salsa

salsaInstance.configReady = true; // ensure the gatekeeper is bypassed.
salsaInstance.Initialize(); // this performs the helper data baking.

For EmoteR, call module initialization for EmoteR. Leverage the API to perform these functions.

CrazyMinnow.SALSA.Emoter emoterInstance; // reference to Emoter

emoterInstance.configReady = true; // ensure the gatekeeper is bypassed.
emoterInstance.Initialize(); // this performs the helper data baking.

Eyes Requirements

The Eyes workflow is very similar, but has some nuances to consider. Eyes is actually a set of four smaller modules that operate as a related set. The separate mini-modules have their own associated controller data and require baking the controller data from configuration data for each module implemented.

Additionally, once the character model's configuration is complete, several computational gizmos are required for orientation and movement or rotation calculations. The Eyes.Initialize() method is used to perform this requirement.

CrazyMinnow.SALSA.Eyes eyesInstance;

eyesInstance.Initialize(); // configure calculation gizmos

// Bake configuration data into controllers.
eyesInstance.UpdateRuntimeExpressionControllers(ref eyesInstance.heads);
eyesInstance.UpdateRuntimeExpressionControllers(ref eyesInstance.eyes);
eyesInstance.UpdateRuntimeExpressionControllers(ref eyesInstance.blinklids);
eyesInstance.UpdateRuntimeExpressionControllers(ref eyesInstance.tracklids);