Shader Graphs

Instead of assigning a constant value to a parameter in a shader definition, it is possible to assign a shader:

    "parameter_name" = "shader_name"  

For parameters assigned in this way, no value is stored in the shader definition. It is obtained by calling shader_name at runtime. For example, if the ambient parameter of a material shader has the constant value 1 0 0, it is always red, but if another shader is assigned to it that other shader is called when the material shader asks for the value using the mi_eval function or one of its derivatives. The other shader could be a texture shader, for example, resulting in a textured ambient value.

The return type of the assigned shader must agree with the parameter type. If the return type of the assigned shader is struct, it is possible to select a structure member by appending a period and the name of the struct member to the shader name. Consider the following assignment:

     declare shader
        color "phong" (color "ambient",
                       color "diffuse",
                       color "specular")
        version 1
     end declare

     declare shader
        struct {color "a", color "b"}
              "texture" (color texture "picture")
        version 1
     end declare

     color texture "fluffy" "/tmp/image.rgb"

     shader "map" "texture" (
        "picture"   "fluffy")

     shader "mtlsh" "phong" (
        "ambient"   0.3 0.3 0.3,
        "diffuse"   = "map.a",
        "specular"  = "map.b")

This defines a material shader that does not support texturing in any way because it has no parameters of type shader or color texture. Yet, shader assignments allow its diffuse and specular components to be textured without the phong shader being aware of it. Whenever phong accesses its ambient parameter value by calling mi_eval, it gets a constant color 0.3 0.3 0.3. When it accesses its diffuse or specular color, a call to the named shader map results (which actually calls shader texture), whose result is then returned to the phong shader.

In this example, the map shader returns two colors a and b, which are selected in the shader assignment by appending .a and .b to map. (For this reason periods should be avoided in parameter names.) If the shader had returned only a single color, only "map" would have been assigned, without appending a period and a structure member name.

In the example, map is assigned twice. Obviously it is not desirable to actually call it twice, because the first call will already have set both its a and b return values. After the first call from a shader, mental ray caches the return value to avoid further calls. As soon as the shader phong returns, the cache is discarded to ensure that the next call to phong, most likely with a different state, calls map instead of using a stale cache.

Note that shaders that support shader graphs must use the mi_eval function to access their parameters. This was done to ensure that only those assigned shaders whose values are actually used are evaluated. For example, a material shader that has two color parameters, one for the front and one for the back side of the surface, will access only one of its parameters by using mi_eval only once.

To see how the phong shader is implemented as a C shader, see section paramassign.

The advantage of shader assignment is that it is not necessary to write shaders to accept procedural values. Without shader assignments, a simple Phong material shader would need parameters of type shader or color texture in addition to the standard ambient, diffuse, and specular parameters. Shader assignment allows writing small, reusable "base shaders" that can be easily combined into powerful shader graphs, instead of writing large monolithic shaders that are hard to modify and inflexible to use.

The third form of parameter assigning using the interface keyword is available only inside phenomena, which will be discussed next.

Copyright © 1986-2009 by mental images GmbH