next up previous contents
Next: Mental Ray Up: How Do Several Shaders Previous: How Do Several Shaders   Contents

RenderMan

Let's start with the interaction between light and surface shaders. I explain the details while we are doing a few tests. Please read section 5 for more details about light shaders.

We create a very simple RIB file:

# test.rib
Exposure 1.0 2.2
Display "test.tiff" "file" "rgba"
Format 508 380 1.0
Projection "perspective" "fov" [ 90 ]
WorldBegin
  LightSource "pointlight" 0
  AttributeBegin
    Surface "plastic"
    Translate 0 0 1
    Patch "bilinear" 
    "P" [ -1.0 -1.0 0.0 1.0 -1.0 0.0 -1.0 1.0 0.0 1.0 1.0 0.0 ] 
  AttributeEnd
WorldEnd

You could render this RIB file e.g. with render test.rib and check that there is something in front of your camera before you start doing your own tests. It's a simple bilinear patch with 4 control points in front of the camera with a field of view of 90 degrees and translated along the positive z-axis18.

Now we start to replace the surface shader and the light shader with our own shaders. But first change the resolution of the resulting image. Change the line Format 508 380 1.0 to Format 5 4 1.0. This will reduce the resolution to only a few pixels in each direction. You will soon see why. The next thing which might help compiling your shaders every time you change a line is to create a Makefile and automate the rendering and shader compiling:

# Makefile

SHADER = shader
RENDER = render
EXT = slo

all: test.tiff

myLight.$(EXT): myLight.sl
        $(SHADER) myLight.sl

mySurface.$(EXT): mySurface.sl
        $(SHADER) mySurface.sl

test.tiff: test.rib myLight.$(EXT) mySurface.$(EXT)
        $(RENDER) test.rib

clean:
        -rm -f *~ *.$(EXT) test.tiff

Now you just type make to compile the shaders and render a picture called test.tiff. Go back to the RIB file and change the lines where the shaders are called to use your own light and surface shader:

...
  LightSource "myLight" 0
  AttributeBegin
    Surface "mySurface"
...

We are ready to create the two shaders. For a start we just print some information that the shader was called. That's why we reduced the image resolution to create only a few lines of output. The light shader should look like this:

/* myLight */

light 
myLight()
{
  printf("myLight\n");
}

The surface shader looks very similar:

/* mySurface */

surface 
mySurface()
{
  printf("mySurface\n");
}

But if you render the image only output from the surface shader is printed. That means the light shader never gets called. OK, maybe we should use the output variables. Leave the printf line as it is but add other lines to make the surface shader act like the standard constant shader:

/* mySurface */

surface 
mySurface()
{
  printf("mySurface\n");
  Oi = Os;
  Ci = Os * Cs;
}

The light shader should be similar to the standard ambientlight:

/* myLight */

light 
myLight()
{
  printf("myLight\n");
  Cl = color (1.0, 1.0, 1.0);
}

We don't use shader parameters at the moment. Most of the time you will start with fixed values in your shaders and make them step by step available as shader parameters later to give the users of your shaders the possibility to change things from outside your shader without changing the shader itself anymore.

If you run the test again you will notice that the light shader still is not called. Why? Well, the surface shader has to call some functions to invoke the light shader. Let's replace the last line in the surface shader:

Ci = Os * Cs * ambient();

Our ambient light source shader will now be called. The light shader acts like an ambient light source because it does not use a illuminate or solar statement. See section 5.1.

The output of the shaders might look different for several renderers. For PRMan first only calls to the surface shader are made; after that only calls to the light shader are made19. For BMRT or AIR the calls are intermixed; one call to the surface shader, one call to the light shader, etc. This shouldn't concern you too much as long as both shaders create the same output image for all RenderMan compliant renderers. But it shows for the first time that things might be handled differently for all this RenderMan compliant renderers.

For a complete list of Shading and Lighting Functions I refer to the The RenderMan Interface document from Pixar. Here just a list of functions without further details20:

Now let's have a look at some of this functions and talk about something else which is important in a real production pipeline. It's very convenient to render several passes of a scene and do adjustments afterwards with a compositing software.

Set the resolution back to the values it had before, get rid of the printf() statements, and change the surface shader to:

/* mySurface */

surface 
mySurface(float roughness = 0.1)
{
  normal Nf = faceforward(normalize(N), I);

  Oi = color 1;
  Ci = (color(1, 0, 0) * ambient() + 
        color(0, 1, 0) * diffuse(Nf) + 
        color(0, 0, 1) * specular(Nf, normalize(-I), roughness));
}

The result is not very exciting because the light shader still returns only the ambient lighting. Let's change that21:

/* myLight */

light 
myLight(
        float intensity = 1;
        color lightcolor = 1;
        point from = point "shader" (0,0,0);
        )
{
  illuminate(from)
    Cl = intensity * lightcolor / L.L;
}

Basically you separate and color encode the ambient, diffuse, and specular contribution. The ambient term is in the red component, the diffuse term in the green component, and the specular in the blue component. In the compositing program you can separate the three components into three grey scale pictures, multiply it with any color you want, apply filters e.g. blur the highlight from the specular contribution more in x-direction than in the y-direction etc. This can save a lot of rendering time for a complicated geometry to match the lighting and coloring conditions in life action. You could do that in theory for every light. I use it here only to show you that you should keep the post-production in mind and that you might use basically the same RIB file for several passes and modify certain parts to create several pictures which are useful for compositors.

The example scene is not very interesting. So replace the linear patch through a sphere and add an ambient light source to get an extra light contribution:

# test.rib
Exposure 1.0 2.2
Display "test.tiff" "file" "rgba"
Format 508 380 1.0
Projection "perspective" "fov" [ 90 ]
WorldBegin
  LightSource "ambientlight" 0
  LightSource "myLight" 1
  AttributeBegin
    Surface "mySurface"
    Translate 0 0 2
    Sphere 1 -1 1 360
  AttributeEnd
WorldEnd

Exercises:

  1. Try to use the separating into passes with real production scenes.

  2. Try to match the lighting of a photograph with real actors or buildings by adding virtual components.


next up previous contents
Next: Mental Ray Up: How Do Several Shaders Previous: How Do Several Shaders   Contents
Jan Walter 2004-02-09