In section 3 I mentioned a RenderMan
shader called defaultsurface which allows to render an image
without any light and surface shaders used in the RIB file. We want
to write a similar shader for mental ray now. Let's have a
look how AIR26 implements the
defaultsurface shader:
surface defaultsurface (float Ka=.2, Kd=.8)
{
Oi=Os;
Ci=Os*Cs*(Ka+Kd*abs(normalize(I).normalize(N)));
}
The implementation of the mental ray shader is straight forward. The
only difference is that mental ray has no global state for the current
surface color and opacity. The RenderMan shader takes the values of
Os and Cs into account. This color values can be set in
the RIB file by using Opacity or Color. If you want a
similar behaviour within the mental ray shader you should use
additional shader parameters for the color and opacity values. Here is
the header file for the mental ray shader:
# myDefaultSurface.mi
declare shader
color "myDefaultSurface" (
scalar "Ka",
scalar "Kd"
)
version 1
apply material
end declare
To use this shader in a MI file I changed the example from section 3.1 a bit:
...
link "myDefaultSurface.so"
$include <myDefaultSurface.mi>
...
material "mtl"
opaque
"myDefaultSurface" (
"Ka" 0.2,
"Kd" 0.8
)
end material
...
object "Monkey"
visible trace shadow
tag 1
group
0.4375 0.1640625 0.765625
...
p "mtl" 504 322 320 390
end group
end object
instance "Monkey_inst" "Monkey"
transform
1.0 0.0 0.0 0.0
0.0 1.0 0.0 0.0
0.0 0.0 1.0 0.0
0.0 0.0 5.0 1.0
end instance
instgroup "rootgrp"
"Camera_inst"
"Monkey_inst"
end instgroup
render "rootgrp" "Camera_inst" "opt"
First of all you have to link your shared library and include the appropriate header file. If you can't copy the compiled shader and the header file to a place where mental ray can find it -- e.g. because you don't have root permissions on an Unix system -- you can specify the full path in the MI file.
After having defined the shader and its parameters as a material
within the MI file you can use the material in the definition of the
Monkey object. Notice that there is only a camera and one
geometry object defined -- no lights. The shader itself looks like
this:
/* myDefaultSurface.c */
#include <shader.h>
struct myDefaultSurface
{
miScalar Ka;
miScalar Kd;
};
DLLEXPORT miBoolean
myDefaultSurface(
miColor* result,
miState* state,
struct myDefaultSurface* paras
)
{
miScalar Ka, Kd;
miScalar abs_dot_nd;
/* get parameters */
Ka = *mi_eval_scalar(¶s->Ka);
Kd = *mi_eval_scalar(¶s->Kd);
/* dot product of the normal and the direction vector */
abs_dot_nd = fabs(state->dot_nd);
/* result */
result->r = Ka + Kd * abs_dot_nd;
result->g = Ka + Kd * abs_dot_nd;
result->b = Ka + Kd * abs_dot_nd;
result->a = 1.0;
return(miTRUE);
}
Notice that you don't have to calculate the dot product of the normal and the direction vector yourself because it's already stored in the state.