This section shows how to create a .mi file that uses a custom shader that is linked at runtime. This example uses a texture shader, but the same procedure is used to create and link any other type of shader.
Step 1: Writing the Shader Source
This texture shader operates in object space and colors the object into eight cubes that meet at the object coordinate origin. A cube mapped with this texture looks like a Rubik's cube for beginners that consists of eight subcubes, each with a different color. The brightness and saturation of the colors is determined by the shader parameters min and max.
#include <stdio.h> #include <mi/shader.h> struct mytexture { miScalar min, max; }; int mytexture_version(void) {return(1);} miBoolean mytexture( miColor *result, miState *state, struct mytexture *paras) { miVector vec; miScalar min, max; mi_point_to_object(state, &vec, &state->point); min = *mi_eval_scalar(¶s->min); max = *mi_eval_scalar(¶s->max); result->r = vec.x < 0 ? min : max; result->g = vec.y < 0 ? min : max; result->b = vec.z < 0 ? min : max; result->a = 1; return(miTRUE); }
This code should be written to a file mytexture.c.
Step 2: Compiling and Linking
There are several ways to integrate this shader into a scene file: placing the source code directly into the .mi file with $code and $end code statements, referencing the source file with a code statement, or compiling the source and referencing the object code with a link statement. The recommended method, and also the fastest method, is to create a DSO (Dynamic Shared Object) file on Unix systems, or a DLL on Windows NT systems. To do this, the shader must be compiled and linked manually:
% cc -O2 -shared -o mytexture.so mytexture.c
This example uses SGI syntax; other compilers require different command lines. See the beginning of this chapter for the commands required for different types of systems. You may also want to specify the -g option for debugging, -O for optimization, or -Idirectory to tell the compiler where the directory containing the shader.h file can be found (refer to the compiler documentation for details). After this command, there is a mytexture.so DSO in the current directory; move it to a place accessible to all hosts, for example with
% mv mytexture.so /usr/share/local
Assuming a directory /usr/share/local exists and is accessible to you. You may also choose a directory such as /usr/tmp, but since this directory is not normally accessible from other hosts that you want to use as servers (at least not under this name), you will have to copy mytexture.so to /usr/tmp on the other hosts too.
Step 3: Linking and Declaring the Shader
Now the shader needs to be linked and declared in the .mi scene file that contains the object or objects to be mapped with the new texture. Linking means that the DSO (or DLL) becomes callable by mental ray, and the declaration informs mental ray about the shader parameters:
link "/usr/share/local/mytexture.so" declare shader color "mytexture" (scalar "min", scalar "max") version 1 end declare
It is important that the declaration matches the type and order of the C declaration in the source file, struct mytexture. These lines should be added near the beginning of the .mi file, before the first use and before the frame statement if there is one. For complicated DSOs, it is recommended to put all declarations for the library into a separate file mytexture.mi, and use a $include statement:
link "/usr/share/local/mytexture.so" $include "/usr/share/local/mytexture.mi"
Either way, the library must be linked before the declaration is given because mental ray makes sure that a declared shader exists.
Step 4: Using the Shader
Now the shader can be used in a real .mi file. The following example puts the texture on a cube. Note the transform statements; they describe the camera and object transformations to allow the call to mi_point_to_object in the shader to work correctly.
verbose on $include <base.mi> link "base.so" link "/usr/share/local/mytexture.so" declare shader color "mytexture" (scalar "min", scalar "max") version 1 end declare options "opt" end options camera "cam" output "rgb" "demo.rgb" focal 1.0 aperture 1.0 aspect 1.0 resolution 500 500 end camera instance "cam_inst" "cam" end instance light "light" "mib_light_point" ("color" 1.0 1.0 1.0) origin 15.614674 14.370044 -10.951728 end light instance "light_inst" "light" end instance color texture "tex" "mytexture" ( "min" 0.3, "max" 1.0 ) material "mtl" opaque "mib_illum_phong" ( "ambience" .3 .3 .3, "ambient" = "tex", "diffuse" = "tex", "specular" 1 1 1, "exponent" 50, "lights" [ "light_inst" ] ) end material object "cube" visible shadow trace group "mesh" -7.288994 -2.709234 -23.455124 -0.695147 -7.196985 -17.423435 -7.288994 5.313703 -17.485828 -0.695147 0.825951 -11.454139 0.229063 1.226829 -28.745323 6.822910 -3.260922 -22.713634 0.229063 9.249765 -22.776028 6.822910 4.762013 -16.744339 v 0 v 1 v 3 v 2 v 1 v 5 v 7 v 3 v 5 v 4 v 6 v 7 v 4 v 0 v 2 v 6 v 4 v 5 v 1 v 0 v 2 v 3 v 7 v 6 p "mtl" 0 1 2 3 p 4 5 6 7 p 8 9 10 11 p 12 13 14 15 p 16 17 18 19 p 20 21 22 23 end group end object instance "cube_inst" "cube" transform 0.751806 0.000000 0.659385 0.0 0.393606 0.802294 -0.448775 0.0 -0.529020 0.596930 0.603169 0.0 -10.861954 11.174661 12.737814 1.0 end instance instgroup "root" "cam_inst" "light_inst" "cube_inst" end instgroup render "root" "cam_inst" "opt"