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:
- Rendering:
- miSHADERSTATE_STATE_INIT when a tile of the image starts.
- miSHADERSTATE_SAMPLE_INIT before each eye ray.
- miSHADERSTATE_SAMPLE_EXIT after each eye ray, but
before the result is stored in the frame buffers.
- miSHADERSTATE_STATE_EXIT when a tile of the image finishes.
- Displacement:
- miSHADERSTATE_STATE_INIT for each displaced subobject.
- miSHADERSTATE_SAMPLE_INIT before each
displacement shader call.
- miSHADERSTATE_SAMPLE_EXIT directly after each
displacement shader call.
- miSHADERSTATE_STATE_EXIT after a subobject has been displaced.
- Lightmapping:
- miSHADERSTATE_STATE_INIT before the first vertex of
each subobject. (Objects may be split into subobjects if they are
too large.)
- miSHADERSTATE_SAMPLE_INIT before each
lightmap shader call, in either vertex
or output mode.
- miSHADERSTATE_SAMPLE_EXIT after each
lightmap shader call, in either vertex
or output mode.
- miSHADERSTATE_STATE_EXIT after the
lightmap shader has been called in
output mode (ie. for the last time for this subobject).
- Photons:
- miSHADERSTATE_STATE_INIT before starting to cast a
bundle of photons. A bundle has about 5000-10000 photons.
- miSHADERSTATE_SAMPLE_INIT before a photon is
cast.
- miSHADERSTATE_SAMPLE_EXIT after a photon has been
cast.
- miSHADERSTATE_STATE_EXIT after finishing the bundle of
photons.
- Finalgather preprocessing before image rendering starts:
- miSHADERSTATE_STATE_INIT before a set of finalgather
points is set.
- miSHADERSTATE_SAMPLE_INIT before each finalgather
point is set. (Each point involves a large number of finalgather
rays.)
- miSHADERSTATE_SAMPLE_EXIT after each finalgather point
is finished.
- miSHADERSTATE_STATE_EXIT after the set of finalgather
points is finished.
- Geometry shader:
- miSHADERSTATE_STATE_INIT before each geometry shader
call.
- miSHADERSTATE_SAMPLE_INIT before each geometry shader
call.
- miSHADERSTATE_SAMPLE_EXIT after each geometry shader
call.
- miSHADERSTATE_STATE_EXIT after each geometry shader
call.
- Output shader:
- miSHADERSTATE_STATE_INIT before the first output
shader is called.
- miSHADERSTATE_SAMPLE_INIT before each
output shader call.
- miSHADERSTATE_SAMPLE_EXIT after each
output shader call.
- miSHADERSTATE_STATE_EXIT after the last output shader
has been called.
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.