Thursday, April 7, 2011

Writing mental ray shaders: Normals as Colors Part I

A shader that visualizes the surface normal.

1. Find the surface normal at point p
2. Assign xyz values to rgb at point p

Mi File
declare shader
 color "normals_as_colors" ();
apply material
end declare

C File
#include "shader.h"

int normals_as_colors_version(void) { return(1); }

miBoolean normals_as_colors(miColor *result, miState *state, void *params) {
 miVector normal;
 mi_vector_to_object(state, &normal, &state->normal);
 result->r = (normal.x + 1) / 2;
 result->g = (normal.y + 1) / 2;
 result->b = (normal.z + 1) / 2;
 result->a = 1.0;
 return miTRUE;

Q. Why not write it like this?

result->r = (state->normal.x + 1) / 2;
 result->g = (state->normal.y + 1) / 2;
 result->b = (state->normal.z + 1) / 2;

A. It's because state->normal is in internal space, which just happens to be the same as object space.

From the mental ray documentation,

"Internal space is the coordinate system mental ray uses to present intersection points and other points and vectors to shaders. All points and vectors in the state are presented in internal space, namely org, dir, point, normal, normal_geom, motion and derivs, except bump basis vectors which are in object space. The actual meaning of internal space is left undefined, it varies between different versions of mental ray and depends on the space given in the options block of the scene. A shader must not assume that internal space is identical to world space, even though this is true in most scenes.

Most shaders never need to transform between spaces. Texture shaders frequently need to operate in object space. For example, in order to apply bump basis vectors to state→normal, the normal must be transformed to object space before the bump basis vectors are applied, and back to internal space before the result is passed to any mental ray function such as mi_trace_reflection. mental ray offers 18 functions to convert points, vectors and normals between coordinate spaces. 

Conflicting? Yes, so do it the safe way.

r := r ⁄ ||r|| (If r is a null vector, leave r unchanged.)
*state, *r, *v
Convert internal vector v to the object space of the current object (illuminated point), r.

1. Create a normals as colors shader that uses world space.
2. Create a normals as colors shader that uses camera space.
3. Better yet, create a shader that can choose which space to display the color in.


Post a Comment