Curve and Expressioned Parameters ********************************* |sparkles| **New in Katana 8.5** Introduction ============ One of the design goals of :kat:node:`UsdSuperLayer` is not just to express the *result* in USD, but also the *user’s intent*. When an artist sets a keyframed curve or writes an expression to drive a parameter value, that intent is captured, evaluated, and then expressed cleanly in USD without leaving Katana-specific data behind. Overview ^^^^^^^^ This workflow proceeds through three stages: **1. Setting** When a parameter is authored via the UI or Python, :kat:node:`UsdSuperLayer` writes metadata into the `Content Layer` using the ``FnKatNodeAPI`` schema. The definition of this schema resides in the ``FnUsdShim`` source code. Schema fields: .. list-table:: :header-rows: 1 :widths: 20 80 * - Field - Description * - ``valueMode`` - Always present. Specifies the type of authored value: ``constant``, ``curve``, or ``expression``. * - ``curve`` - Optional. Serialized Katana FCurve in XML format. * - ``expression`` - Optional. Expression as a string. Whenever the parameter value changes, the schema is updated to reflect the new mode: - Switching *into* ``curve`` or ``expression`` populates the corresponding field. - Switching *out of* ``curve`` or ``expression`` removes the ``FnKatNodeAPI`` data from the prim. Katana parameters may still hold onto dormant values locally (for example, expressions or curves on enableable parameters), but these are not retained in the `Content Layer`. This mirrors Katana’s typical parameter behavior and ensures that when all parameters are reset to defaults, the prim is left in an unmodified state. **2. Evaluation** At evaluation time: - The `Content Layer` is duplicated to a temporary layer that will be serialized and sent to the node’s Engine. - If ``valueMode`` is ``constant``, the authored value is used directly. - If ``valueMode`` is ``curve`` or ``expression``, the parameter is evaluated at the current Graph State by re-querying ``NotifyParameterChange`` on the ``ParameterHandler`` plug-in responsible for the parameter. This allows the ``ParameterHandler`` to update the `Content Layer` with the appropriate frame-specific values for the current evaluation Graph State. **3. Pruning** After evaluation, the ``FnKatNodeAPI`` schema is stripped from the `Content Layer`. Only resolved USD values remain, leaving a clean, portable USD stage with no Katana-specific metadata. .. tip:: It's possible to disable pruning (i.e. for debugging purposes) by unchecking the ``removeIntermediateData`` parameter on the internal `_UsdLayerNode` within the UsdSuperLayer super tool (press ``Ctrl+Enter`` to enter a supertool node and see its internal nodes). Examples ^^^^^^^^ The following example shows how to set an expression on a parameter from the USD side. This demonstrates how Katana not only drives USD stage content but can also react to changes recorded in the ``Content Layer``. .. code-block:: python import usg import NodegraphAPI from NodesUsdAPI.UsdSuperLayer import Utils # Create a UsdSuperLayer node in the scene with a cylinderlight on it node = NodegraphAPI.CreateNode("UsdSuperLayer", NodegraphAPI.GetRootNode()) controller = node.getStageSubtreeController() controller.createPrim("cylinderlight", "CylinderLight") node.syncLayerAndParameters() node.buildParametersForPrimPath("/root/cylinderlight") param = node.getParameter( "properties.cylinderlight.fnPropertiesGroup.PropertiesParametersHandlerPlugin.inputs.intensity.value" ) # Get the equivalent USD data in the Content Layer attached to the node primPath = controller.getBasePath().appendChild("cylinderlight") prim = controller.getContentLayer().getPrimAtPath(primPath) # Apply the FnKatNodeAPI schema to signal an expression on the intensity attribute instanceName = Utils.FnKatNodeAPISchemaHolder.GetInstanceNameFromParameter(param) schema = Utils.FnKatNodeAPISchemaHolder.Apply(prim, instanceName) valueModeAttr = schema.getValueModeAttr() or schema.createValueModeAttr() valueModeAttr.set(usg.Token(Utils.FnKatNodeAPISchemaHolder.VALUE_MODE.EXPRESSION)) expressionAttr = schema.getExpressionAttr() or schema.createExpressionAttr() expressionAttr.set("frame") # sync with Katana node.syncLayerAndParameters() This produces a ``Content Layer`` entry such as the following: .. code-block:: cpp #usda 1.0 def "root" { def CylinderLight "cylinderlight" ( prepend apiSchemas = ["FnKatNodeAPI:PropertiesParametersHandlerPlugin:inputs:intensity:value"] ) { uniform string fnKatNodeAPI:PropertiesParametersHandlerPlugin:inputs:intensity:value:expression = "frame" uniform token fnKatNodeAPI:PropertiesParametersHandlerPlugin:inputs:intensity:value:valueMode = "expression" } } When Katana evaluates the engine chain, the prims containing the ``FnKatNodeAPI`` schema are traversed and the parameters they relate to are requeried with the evaluation for the parameter value at the given Graph State. This round-trip ensures both *user intent* and *final result* are preserved. .. |sparkles| unicode:: U+2728