This section contains some more advanced RenderMan© concepts. One should be familiar with the basics of shader writing before reading this section.
As explained in Integration with Softimage, 3Delight for Softimage automatically translates Softimage shaders to compiled RenderMan© shaders. This means that no shader programming is necessary to use 3Delight for Softimage. However, it is logical to provide Softimage users with the added flexibility of using RenderMan© shaders, if needed. The following sections explain how to connect RenderMan© shaders and how to write shaders that are tightly integrated into Softimage.
It is possible to import custom RenderMan© shader nodes to be used along the standard Softimage nodes in the Render Tree. The imported RenderMan© shader must contain a "surface" method and be compiled using the shaderdl
utility. To load the shader into Softimage you must use the RendermanShaderImport
script command, as in:
RendermanShaderImport("full\\path\\to\\sdl")
The new node will appear in the 3Delight category of the Preset Manager of the Render Tree.
It is possible for the shader writer to provide additional information with regards to the UI that will be used to show the different shader parameters (such as parameter ranges, grouping, etc.). Usually, this is done through SPDL files but in this instance it is 3Delight for Softimage who builds the SPDL automatically from the compiled shader. To specify path where SPDL will be created you must use second argument of RendermanShaderImport
:
RendermanShaderImport("full\\path\\to\\sdl", "spdl\\directory")
The mechanism through which the shader writer can define such UI elements is called "shader annotations". An annotation is added using the #pragma
preprocessor directive. Its general form is:
#pragma annotation <shader_param_name> "annotation[;annotation;...];"
One such shader annotation is very handy and allows for grouping logically related parameters. The grouping syntax is:
#pragma annotation "grouping" "<group>/[<subgroup>/...]<parameter name>;"
As an example, the following annotation will create a group labeled `Hair Color' and put the `tipcolor' parameter in it.
#pragma annotation "grouping" "hairColor/tipcolor;"
It is possible to define any number of group levels; for instance:
#pragma annotation "grouping" "hair/hairColor/tipcolor;"
would create a 'Hair' group, then create a 'Hair Color' group inside the 'Hair' group, and finally insert the 'tipcolor' parameter there. The parameters will appear in the order they are annotated.
It is possible to specify presets in the shader using annotation. A preset is a collection of parameter settings. Following example specifies a preset with name `Bright' and parameter `i_F' with value `0.5':
#pragma annotation preset:Bright "i_F=0.5;"
Other accepted annotations are listed in the table below below.
Annotation | Description |
---|---|
label=<label text> | Specifies a label for the parameter. When no label annotation is supplied, the parameter's label is the parameter name itself. |
hide=<true/parameter_name> | When true, the parameter will not be visible in the user interface. It's also possible to specify a checkbox parameter. If this checkbox parameter is disabled, the current parameter will not be visible in the UI. |
insensitive=<parameter_name> | Specifies parameter that makes the current parameter insensitive. |
disable=<true/false> | When true, the parameter will not be generated. |
value=<value> | Specifies default value of the parameter. |
min=<value> | Specifies min and max values for the parameter. |
hint=<hint text> | Specifies description of the parameter. |
type=<type> | Specifies the type of parameter to create. The supported types are: |
The following illustrates how parameter annotations can be constructed:
#pragma annotation F "label=Value;" #pragma annotation C "label=Color;" #pragma annotation i_F "label=Value;" #pragma annotation i_C "label=Color;" #pragma annotation i_F "default=0.5;" #pragma annotation i_C "default=0.75 0.5 0.0;" #pragma annotation F "min=-1;max=1;" #pragma annotation i_F "min=-1;max=1;" #pragma annotation grouping "Shader's Parameters/F;" #pragma annotation grouping "Shader's Parameters/C;" #pragma annotation grouping "Method's Parameters/i_F;" #pragma annotation grouping "Method's Parameters/i_C;" #pragma annotation preset:<Default> "none" #pragma annotation preset:Yellow "i_F=0.75;" #pragma annotation preset:Yellow "i_C=1 0 0;" #pragma annotation preset:Yellow "F=0.75;" #pragma annotation preset:Yellow "C=0 1 0;" #pragma annotation preset:Black "i_F=0;F=0;" class coshadertest( float F = 0.5; color C = 1;) { public void surface( output color Ci, Oi; float i_F = 1; color i_C = 1;) { Ci = F*C + i_F*i_C; Oi = 1; } }
Important
This sections show how to connect RenderMan© shaders using a special object property. This method will be deprecated so users should use the method described in RenderMan Shaders in the RenderTree.
Connecting a RenderMan© shader is a three step process:
Please note the following important details:
All Softimage vertex properties (such as vertex colors and UV coordinates) are available to shader writers. Accessing a vertex property is as simple as naming it in the parameters list of the shader.
Note
If there is 3Delight attributes attached to geometry, make sure that Export Vertex Properties is 'on'. This parameter is on by default, as explained in 3Delight Attributes.
The following listing shows how to access the Vertex_Color
vertex property.
surface test( varying float Vertex_Color[4] = 0; ) { /* Put the color in the surface color */ Ci = color( Vertex_Color[0], Vertex_Color[1], Vertex_Color[2] ); }
Two noteworthy details about example above:
varying
keyword is needed in front of the parameter since vertex colours vary across the surface.The following example shows how to access a UVW Softimage property named Texture_Projection.
surface test( string texturename = ""; varying float Texture_Projection[3] = 0; ) { /* Access a texture using the given UVs */ Ci = texture( texturename, Texture_Projection[0], Texture_Projection[1] ); }
Note that we are using a float[3]
instead of a point
in the previous example to declare the parameter. This is needed because a point would have been transformed by the transformation matrix applied to the underlying object; passing an array of floats bypasses this "problem".
All Softimage render channels are easily accessed by naming them as output varying
shader parameters. The names are the same as in the Softimage interface: 'Diffuse' for the diffuse channel, 'Specular' for the specular channel, 'Ambient' for the ambient channel and so on. The following example shows an example shader that sets some of Softimage render channels.
surface renderchannels( output varying color Specular = 0; output varying color Diffuse = 0; output varying float Depth = 0; ) { /* This will set the Diffuse/Specular render channels in Softimage */ Specular = noise( P ); Diffuse = diffuse( N ); /* Store the depth, in Softimage infinity is set to 0. */ Depth = depth(P); if( Depth > 1e36 ) Depth = 0; /* Put some different color pattern in the color */ Ci = cellnoise( P * 2 ); Ci *= Oi; }
Accessing store-in render channels is similarly easy: the store-in has to be declared as parameter of the shader, with the correct type.
As explained in Features Summary, 3Delight for Softimage can render Softimage curves of any shape and of any degree. Since Softimage does not allow connecting a material to such geometric primitives, the only option for shading is to assign a RenderMan© shader. A few remarks:
softimage_curve_length
variable so shader writers can have access to it by declaring it as a parameter of the shader.Next listing gives a simple example of such a renderman shader. Note the presence of the softimage_curve_length variable that is available to shader writers and automatically passed as a primvar to all curve primitives.
/* A simple shader that demonstrates how to cut a curve at a specific length. This example shows how to: -- access curve's length -- set the opacity using an anti-aliased step function */ surface curve_cutoff( float softimage_curve_length = 0; /* This is set by 3Delight for Softimage */ float cutoff = 0; ) { /* compute distance from root */ float current_length = v * softimage_curve_length; float f = filterstep( current_length, cutoff ); /* Opacity becomes 0 after the cutoff */ Oi = f; /* Set the color to white and modulate by opacity as usual in RenderMan shaders */ Ci = 1 * Oi; }
Reference geometry can be output as the usual Pref and Nref RenderMan© primvars by enabling reference geometry output in Geometry. The following example illustrates how to access the reference geometry from inside a shader.
surface prefaccess( varying point Pref = 0; varying normal Nref = normal(0, 0, 1); ) { Ci = diffuse( Nref ) * noise( Pref ); }
Note that exporting reference geometry will double the size of the object so this feature should be enabled only when strictly necessary.
It is possible to access clusters' sort order property from inside a RenderMan© shader as shown in the example below. This is an easy way for a TD to create clusters and write particular code for each one of them.
Note
To export the cluster sort order, it is necessary to attach 3Delight attributes to geometry and switch the Export Cluster Sort Order property to 'on'. Refer to 3Delight Attributes.
surface test( uniform float softimage_cluster_sort_order = 0; ) { /* Just put the sort order as a gray scale value */ Ci = softimage_cluster_sort_order / 255; }
Note that a uniform
variable is enough here since the sort order of each cluster doesn't vary across one single polygon.