Dynamic Parameters ================== A sub-set of nodes in Katana feature "dynamic" parameters; dynamic in that their existence on a node is not fixed at node creation time, but rather is on attributes from the incoming scene or some other asynchronous process. For example, upon adding a shader to a :kat:node:`Material` node, Katana must query the renderer for the set of parameters the shader exposes, as well as their default values. Until these queries complete and the :kat:ui:`Parameters` tab is updated, the parameters representing the various shader configuration options do not yet exist. Should you then wish to edit this material in another Material node downstream, this downstream node must query the incoming scene in order to display the existing material's values in the Parameters tab. This effectively means the parameters on the downstream node must update dynamically based on our upstream node. :kat:node:`RenderSettings` is another node that makes use of dynamic parameters. This node depends on the attributes under the :kat:attr:`renderSettings` group attribute at :kat:loc:`/root` and is used for the configuration of render settings such as output resolution. Nodes with dynamic parameters include the following: - :kat:node:`Material` - :kat:node:`NetworkMaterialParameterEdit` - :kat:node:`RendererProceduralArgs` - :kat:node:`RenderOutputDefine` - :kat:node:`TransformEdit` - Shading nodes such as :kat:node:`ArnoldShadingNode` and :kat:node:`PrmanShadingNode` When creating such nodes in Script mode using :func:`NodegraphAPI.CreateNode`, or getting a new reference to an existing node using calls, such as :func:`NodegraphAPI.GetNode`, Katana does not immediately create the dynamic parameters on the node, but only those set locally. While this behavior might go unnoticed when running Katana in UI mode (the :kat:ui:`Parameters` tab is updated with any dynamic parameters in the normal course of UI event processing) it has very real implications if you are running Katana in script mode. In this context, your Python script executes synchronously and there is no UI event loop to take care of updating a node with the result of, say, querying the incoming scene graph or querying the renderer as to which parameters a shader exposes. Instead, before you attempt to access these dependent parameters, you must first call :func:`~Node3D.checkDynamicParameters` on the node. This call blocks until the node's dynamic parameters have been populated. Failing to call this method results in a :func:`~Node3D.getParameter` call returning ``None`` (because the parameter does not yet exist) or returning a parameter whose value is out-of-date (because changes from other parameters would cause its value to be different). As an example, suppose you have an existing scene :file:`myKatanaProject.katana` that contains a :kat:node:`Material` node with a PRMan surface shader, with locally-set values for :kat:param:`Ks`, but with a default value for :kat:param:`Kd`:: # query_parameters.py from Katana import KatanaFile, NodegraphAPI KatanaFile.Load('myKatanaProject.katana') materialNode = NodegraphAPI.GetNode('Material') # This call is necessary to populate the node with its "dynamic" parameters, if # any. materialNode.checkDynamicParameters() # Access the Ks and Kd parameter on the material node. specularParam = materialNode.getParameter('shaders.prmanSurfaceParams.Ks.value') diffuseParam = materialNode.getParameter('shaders.prmanSurfaceParams.Kd.value') # Sanity checks. assert specularParam, "No value for the Ks parameter!" assert diffuseParam, "No value for the Kd parameter!" print("specular=%r, diffuse=%r" % (specularParam.getValue(0.0), diffuseParam.getValue(0.0))) Running this script using ``katana --script query_parameters.py`` prints both the locally-set value for Ks and the default value for :kat:param:`Kd`. Failing to make the call to :func:`~Node3D.checkDynamicParameters` causes the second assertion to be tripped. Below is a more complex example that demonstrates the creation of an Arnold Network Material:: from Katana import NodegraphAPI ############################################################################### imageNode1 = NodegraphAPI.CreateNode('ArnoldShadingNode', NodegraphAPI.GetRootNode()) NodegraphAPI.SetNodePosition(imageNode1, (-75, 200)) imageNode1.getParameter('name').setValue('diff_image', 0.0) imageNode1.getParameter('nodeType').setValue('image', 0.0) # Call checkDynamicParameters() to ensure parameters dependent on "nodeType" # are made available. imageNode1.checkDynamicParameters() imageNode1.getParameter('parameters.filename').createChildString( 'hints', repr({ 'widget': 'filename', 'dstPage': 'basics', 'dstName': 'diff_texture'})) imageNode2 = NodegraphAPI.CreateNode('ArnoldShadingNode', NodegraphAPI.GetRootNode()) NodegraphAPI.SetNodePosition(imageNode2, (75, 200)) imageNode2.getParameter('name').setValue('spec_image', 0.0) imageNode2.getParameter('nodeType').setValue('image', 0.0) # Call checkDynamicParameters() to ensure parameters dependent on "nodeType" # are made available. imageNode2.checkDynamicParameters() imageNode2.getParameter('parameters.filename').createChildString( 'hints', repr({ 'widget': 'filename', 'dstPage': 'basics', 'dstName': 'spec_texture'})) ############################################################################### standardNode = NodegraphAPI.CreateNode('ArnoldShadingNode', NodegraphAPI.GetRootNode()) NodegraphAPI.SetNodePosition(standardNode, (0, 0)) standardNode.getParameter('name').setValue('standard_node', 0.0) standardNode.getParameter('nodeType').setValue('standard', 0.0) # Call checkDynamicParameters() to ensure parameters dependent on "nodeType" # are made available. standardNode.checkDynamicParameters() standardNode.getParameter('parameters.Ks.enable').setValue(1, 0.0) standardNode.getParameter('parameters.Ks.value').setValue(0.7, 0.0) standardNode.getParameter('parameters.Ks_color.enable').setValue(1, 0.0) standardNode.getParameter('parameters.Ks_color.value.i0').setValue(0.2, 0.0) standardNode.getParameter('parameters.Ks_color.value.i1').setValue(0.7, 0.0) standardNode.getParameter('parameters.Ks_color.value.i2').setValue(1.0, 0.0) standardNode.getInputPort('Kd_color').connect(imageNode1.getOutputPort('out')) standardNode.getInputPort('Ks_color').connect(imageNode2.getOutputPort('out')) # Create "hints" parameters that describes how these parameters should be # exposed in the material's public interface. standardNode.getParameter('parameters.Kd').createChildString( 'hints', repr({'dstPage': 'basics', 'dstName': 'Kd'})) standardNode.getParameter('parameters.Ks').createChildString( 'hints', repr({'dstPage': 'basics', 'dstName': 'Ks'})) ############################################################################### networkMaterialNode = NodegraphAPI.CreateNode('NetworkMaterial', NodegraphAPI.GetRootNode()) NodegraphAPI.SetNodePosition(networkMaterialNode, (100, -100)) networkMaterialNode.addInputPort('arnoldSurface') networkMaterialNode.getInputPort('arnoldSurface').connect( standardNode.getOutputPort('out')) .. note:: The code sample above uses the :kat:node:`ArnoldShadingNode` type and only behaves correctly if you are using the Arnold renderer. .. py:currentmodule:: NodegraphAPI .. method:: Node3D.checkDynamicParameters Checks and updates any dynamic parameters, i.e. parameters that rely on values from the incoming scene.