Resolvers

Resolvers are Ops that must be run before actual rendering, in order to get data into the correct final form. Typically they are used for things like material assignments, executing overrides, and calculating the effects of constraints.

The only data the can be passed from one Op to the next is the scene graph, with its attributes. Resolvers are procedural processes that can be executed with just attribute data, which allows us to separate executing procedural process into two stages:

1.   Set up appropriate attributes in the scene graph that define what process to run and any parameters that need to be handed to the procedural.
2.   Run a resolver that reads those attributes and executes the procedural process.

This separation into two stages gives a lot more flexibility than if all procedural processes had to be executed immediately. Because they are only dependent on the correct attributes being set at locations in the scene the configuration to set up the process can be done in a variety of different ways.

For instance, material assignment is based on a single string attribute named materialAssign, which gives the path to the location of the material to be used. This attribute is then used in a resolver called MaterialResolve, which takes the material from the path in the materialAssign attribute and creates a local copy, with all the relevant attributes set to their correct values (taking into account things like material overrides). Because MaterialResolve only looks for an attribute called materialAssign, material assignment can be set up in a number of different ways:

Using MaterialAssign nodes, which set the materialAssign attribute at locations that match the CEL expression on the node.

Using an OpScript to set the value of materialAssign using a Lua script.

Using a custom Op to set the value of materialAssign.

You can also use a LookFile that resolves the correct value for materialAssign onto given objects.

The LookFile system has special behavior for handling materials that have been assigned to an asset. This allows other users to make edits and overrides to material values, while also keeping processing efficient for the majority of cases where there isn’t any need for modifications. This behavior is also designed to handle cases where there may be more than one version of a look file used in a shot and where there are multiple output passes, and overrides may need to be applied to any selection of passes. Renderer procedurals are also handled in a similar manner to materials.

LookFileResolve is designed to look for the existence of materials (and renderer procedurals) at specific locations in the scene graph. If materials are found at these locations then materialAssign attributes are set at locations in the asset that use those materials. This allows you to make modifications, such as material overrides, to all objects that use a material from the LookFile. If no material is found at any of the search locations then the materials from the LookFile are directly applied to locations in the asset without using materialAssign.

The main reason for this system is efficiency: most materials on most assets probably don’t need any modifications, such as overrides, and it is more efficient to simply paste the relevant attribute values onto the asset. However, if you want to apply overrides then it's more convenient to bring the materials directly into the scene and set them up as assigned materials.

To avoid clashes between materials with the same name that are brought in from different LookFiles, a namespace path is used as the location under which the materials are brought in. This is constructed using the following options:

A custom path (specified by a parameter on LookFileOverrideEnable) or a path provided by the asset management system based on the LookFile asset using getUniqueScenegraphLocationFromAssetId().

If the asset management system provides version numbers for look files, the path can either explicitly include the version number, which means that any overrides only apply to assets that use that explicit version LookFile, or a version-less path, which means that any overrides apply to assets that use any version of the LookFile.

Resolvers allow us to keep the data high-level and user meaningful as possible since until the resolver runs the user can directly manipulate the attributes that describe how the process should run instead of only being able to manipulate the data that comes out of the process.

For instance, since material assignment is based on the materialAssign attribute we can:

Change what material an object gets by changing that one attribute’s value.

Change the material on every object that is assigned a specific material by changing the attributes of the original material.

In essence resolvers manipulate the parameters of the process, rather than just the data that comes out of the process, with access to all the tools available in Katana for inspecting, modifying and overriding attributes.