state→volume
variable is called, without
copying the state, as if it had been called as the last operation
of the material shader. Copying the state is not necessary because
the volume shader does not return to the material shader, so it is
not necessary to preserve any variables in the state.
Unless the shadow segment mode is in effect, volume shaders
are also called when a light shader has returned; in this case the
volume shader state→volume
is called once for the
entire distance from the light source to the illuminated point (i.e.,
to the point that caused the material shader that sampled the light to
be called). In shadow segment mode, volume shaders are not
called for light rays but for
every shadow ray segment from the illuminated point towards the
light source. Some volume shaders may decide that they should not
apply to light rays; this can
be done by returning immediately if the state→type
variable is miRAY_LIGHT.
Finally, volume shaders are called after an
environment shader was called. Note,
that if a volume shader is called after the material, light, or other
shader, the return value of that other shader is discarded and the
return value of the volume shader is used. The reason is that a volume
shader can substitute a non-black color even if the original shader has
given up. Volume shaders return miFALSE if no light can pass
through the given volume, and miTRUE if there is a non-black
result color.
Material shaders have two separate state variables dealing with volumes,
volume and refraction_volume. If the material shader casts
a refraction or transparency ray, the tracing function will copy the
refraction volume shader, if there is one, to the volume shader after
copying the state. This means that the next intersection point finds
the refraction volume in state→volume
, which effectively
means that once the ray has entered an object, that object's interior
volume shader is used. However, the material shader is responsible to
detect when a refraction ray exits an object, and overwrite
state→refraction_volume
with an appropriate outside
volume shader, such as state→camera→volume
, or a
volume shader found by following the state→parent
links.
Since volume shaders modify a color calculated by a previous material shader,
environment shader, or light shader, they differ from these shaders in that
they receive an input color in the result argument that they are
expected to modify. A very simple fog volume shader could be written as:
miBoolean myfog( register miColor *result, register miState *state, register struct myfog *paras) { register miScalar fade; register miColor *fogcolor; register miScalar max; if (state->type == miRAY_LIGHT) return(miTRUE); max = *mi_eval_scalar(¶s->maxdist); fogcolor = mi_eval_scalar(¶s->fogcolor); fade = state->dist > max ? 1.0 : state->dist / max; result->r = fade * fogcolor->r + (1-fade) * result->r; result->g = fade * fogcolor->g + (1-fade) * result->g; result->b = fade * fogcolor->b + (1-fade) * result->b; result->a = fade * fogcolor->a + (1-fade) * result->a; return(miTRUE); }This shader linearly fades the input color to
paras→fogcolor
(probably white) within paras→maxdist
internal space units.
Objects more distant are completely lost in
fog. The length of the ray to be modified
can be found in state→dist
, its start point in
state→org
, and its end point in
state→point
. This example shader does not apply to
light rays, light sources can
penetrate fog of any depth because of the miRAY_LIGHT
check. In this case, the shader returns miTRUE anyway
because the shader did not fail; it merely decided not to apply
fog.
If this shader is attached to the camera, the atmosphere surrounding the
scene will contain fog. Every state→volume
will inherit
this camera volume shader, until a refraction or transparency ray is cast.
The ray will copy the material's volume shader,
state→refraction_volume
, if there is one, to
state→volume
, and the ray is now assumed to be in the
object. If the material has no volume shader to be copied, the old
volume shader will remain in place
and will be inherited by subsequent rays.
Some volume shaders employ ray marching
techniques to sample lights from empty space, to achieve effects such as
visible light beams. Before such a shader calls
mi_sample_light, it should store
0 in state→pri
to inform mental ray that there is no
primitive to illuminate, and to not attempt certain optimizations such as
back face elimination. Shaders other than volume shaders may do this too,
but must restore pri before returning. Some
mi_query modes do not work if
pri has been modified.
Volume shader that sample light sources should not only clear
state→pri
but also use this test at the beginning:
if (state->type == miRAY_LIGHT) return(miTRUE);
Since sampling a light causes one or more light rays to be cast, and since these light rays most likely travel through the same volume, they would also call this same volume shader recursively. If the volume shader doesn't realize this and proceeds to cast even more recursive rays, it will get into an infinite recursion until a stack overflow aborts the program. Note that the test should come before all other code, especially mi_eval calls, to avoid unnecessary work and increase performance.
Copyright © 1986, 2015 NVIDIA ARC GmbH. All rights reserved.