State Shaders

State shaders are functions that are invoked to set up and clean up rendering states, and before and after all forms of primary ray casting. They are intended to customize the state, control user data, or manipulate the sample values prior and after various stages of the rendering process. They don't have the limitations of other shader types that are sometimes used for such purposes, like lens shaders. State shaders are attached to the scene options. Multiple state shaders can exist in a scene (typically one per shader package) which are called in a sequence.

mental ray usually uses the same state for a number of related shader calls, such as for all primary rays of a screen-space tile, which means that state shaders are typically called more often in sample than state mode. The mode is passed in the structure passed as the fourth argument. The following calls occur:

Note that sample exit shaders are called immediately after the associated shader call (lens, material, displacement, etc.), and receive the same result pointer as their first argument. This can be used to manipulate returned values, especially in cases like light mapping where no lens shaders are called.

struct state_arg {      /* state shader parameters */
    int     count;
    float   s;
};

typedef struct state_x { /* data to store in shaderstate */
    int     value;
} MyStateExt;

miBoolean state_ext(
    miColor             *result,
    miState             *state,
    struct state_arg    *param,
    miShader_state_arg  *arg)
{
    const char          *key = "StateExtension";
    miBoolean           res = miFALSE;

    if (state->type != miRAY_EYE) {
            /* state shaders may be called in various situations,
             * here we only deal with actual rendering. */
            return(miFALSE);
    }
    switch(arg->op) {
      case miSHADERSTATE_STATE_INIT: {
            MyStateExt myState;     /* prepare state */
            ....
            res = mi_shaderstate_set(state, key, &myState,
                                     sizeof(MyStateExt), miSS_LIFETIME_RECT);
            } break;

      case miSHADERSTATE_STATE_EXIT:
            /* cleanup state */
            ....
            res = mi_shaderstate_set(state, key, NULL, 0, miSS_LIFETIME_RECT);
            break;

      case miSHADERSTATE_SAMPLE_INIT: {
            /* do something before sampling starts */
            MyStateExt *myState = mi_shaderstate_get(state, key, 0);
            .....
            res = miTRUE;
            } break;

      case miSHADERSTATE_SAMPLE_EXIT:
            if (arg->shader_return) {
                    /* if sampling was successful, do something */
                    MyStateExt *myState = mi_shaderstate_get(state,key,0);
                    .....
                    res = miTRUE;
            }
            break;

      default:
            /* this should never happen, add error handling */
            break;
    }
    return res;
}

The declaration of a state shader looks just like a regular shader declaration:

declare shader
    color state_ext(
            integer "count",
            scalar  "s"
    )
    apply state
    version 1
end declare

Note, that the call statement in the .mi scene description language does not cause state shaders to be called.

Copyright © 1986, 2015 NVIDIA ARC GmbH. All rights reserved.