Environment shaders provide a color for rays that leave the scene entirely, and for rays that would exceed the trace depth limit. Environment shaders are called automatically by mental ray if a ray leaves the scene, or when a ray exceeds the trace depth. It can also be done explicitly by shaders using the mi_trace_environment function:
mi_reflection_dir(&dir, state); if (/* do ray tracing? */) mi_trace_reflection (&color, state, &dir); else mi_trace_environment(&color, state, &dir); /* use the returned color */
Environment shaders, like any other shader, may return miFALSE to inform the caller that the environment lookup failed. If mental ray\ falls back on calling the environment shader, it returns the value returned by the environment shader, not necessarily miFALSE.
In both the explicit case and the automatic case (when a ray cast by a function call such as mi_trace_reflection leaves the scene without intersecting with any object) mental ray calls the environment shader found in state→environment. In primary rays, this variable is initialized with the global environment shader in the camera (also found in state→camera→environment). Subsequent material shaders get the environment defined in the material if present, or the camera environment otherwise.
In mental ray 2.x, material shaders never inherit the environment from the parent shader, they always use the environment in the material or the camera. All other types of shaders inherit the environment from the parent shader. In mental ray 3.x, the environment shader is inherited unless the material defines its own.
Here is an example environment shader that uses a texture that covers an infinite sphere around the scene:
struct mib_texture_lookup_spherical { miVector dir; miScalar rotate; miTag tex; }; DLLEXPORT miBoolean mib_lookup_spherical( miColor *result, miState *state, struct mib_texture_lookup_spherical *paras) { miTag tex = *mi_eval_tag(¶s->tex); miVector dir = *mi_eval_vector(¶s->dir); double theta, norm; result->r = result->g = result->b = result->a = 0; if (!tex) return(miFALSE); if (dir.x == 0 && dir.y == 0 && dir.z == 0) mi_vector_to_world(state, &dir, &state->dir); norm = mi_vector_norm(&dir); if (!norm) return(miFALSE); /* * without rotation, 0 is in the direction of the x axis, * increasing in a clockwise direction */ /* avoid calling atan2(0, 0), which return NaN on some platforms */ if (!dir.x && !dir.z) theta = 0.0; else theta = -atan2(dir.x, dir.z) / (2.0*M_PI); theta += *mi_eval_scalar(¶s->rotate) / M_PI; theta -= floor(theta); dir.x = theta; dir.y = asin(dir.y/norm) / M_PI + 0.5; dir.z = 0.0; return(mi_lookup_color_texture(result, state, tex, &dir)); }
This shader uses a parameter in its shader parameter structure,
a tag tex, to specify a texture shader. The texture is
evaluated by calling mi_lookup_color_texture, which
stores storing the texture
coordinate in state→tex
and calls the texture
shader. For a description of texture shaders and how to call them,
see the texture shader section on page texshaderex.
Here is an interesting variation of environment shaders that pastes the environment textures as a background plate, such that it exactly covers the rendered image plane. There are also parameters for zooming and panning to permit a bigger environment, if environment rays are cast outside the normal range.
struct mib_lookup_background { miVector zoom; miVector pan; miBoolean torus_u; miBoolean torus_v; miTag tex; }; DLLEXPORT miBoolean mib_lookup_background( miColor *result, miState *state, struct mib_lookup_background *paras) { miVector *zoom; miVector *pan; miVector coord; miTag tex = *mi_eval_tag(¶s->tex); if (!tex) { result->r = result->g = result->b = result->a = 0; return(miFALSE); } zoom = mi_eval_vector(¶s->zoom); pan = mi_eval_vector(¶s->pan); coord.x = state->raster_x / state->camera->x_resolution * .9999; coord.y = state->raster_y / state->camera->y_resolution * .9999; coord.z = 0; coord.x = pan->x + (zoom->x ? zoom->x * coord.x : coord.x); coord.y = pan->y + (zoom->y ? zoom->y * coord.y : coord.y); if (*mi_eval_boolean(¶s->torus_u)) coord.x -= floor(coord.x); if (*mi_eval_boolean(¶s->torus_v)) coord.x -= floor(coord.y); if (coord.x < 0 || coord.y < 0 || coord.x >= 1 || coord.y >= 1) { result->r = result->g = result->b = result->a = 0; return(miTRUE); } else return(mi_lookup_color_texture(result, state, tex, &coord)); }
Note that this shader returns miTRUE even if the ray missed the environment texture. Effectively, the shader considers all possible rays, and returns black if the texture is missed. If an environment does not cover all possible points around the scene, it should return black or some other valid color.
Copyright © 1986, 2015 NVIDIA ARC GmbH. All rights reserved.