return to main index


Pages 255 to 261 of "Advanced RenderMan" by Gritz and Apodaca provide an introduction to the RSL function cellnoise(). This note attempts to explain how Gritz and Apodaca are using cellnoise to create solid textures.

Basic Code

The sample code used for this tutorial consists of the function and surface shader given in listing 1. The function dist2cell() is almost identical to the code on pages 257 and 258 of the "Advanced RenderMan" book. The function shown in listing 1 differs in that it provides a parameter that enables a user-specified coordinate system to control cellnoise(). The dist2cell() function first transforms the xyz position (p) of the micro-polygon being shaded into what ever spacename is passed to the function from the shader. A nested for-loop finds the distance to the centers of cubes that form a 3x3x3 lattice of imaginary "cells" in the neighborhood of point p. The function returns the distance to the center of the nearest cell. Note that in listing 1 because the call to cellnoise() is commented the nearest cell is always the central cube in the lattice ie. the "cell" (or cube) in which point p is located.

The cell_test shader determines if the value returned from the function is within a user-defined distance called shape_rad. If the value exceeds shape_rad the micro-polygon being shaded is made fully transparent. Before cellnoise() is activated the shader is little more than a rather uninteresting cookie-cutter. This will not be the case after cellnoise() is activated.

Listing 1

float dist2cell(point p; string spacename; float freq)
point pp = transform(spacename, p) * freq;
point thiscell = point(floor(xcomp(pp)) + 0.5,
                       floor(ycomp(pp)) + 0.5,
                       floor(zcomp(pp)) + 0.5);
float dist2nearest = 1000;
uniform float i,j,k;
for(i = -1; i <= 1; i+= 1)
   for(j = -1; j <= 1; j+= 1)
       for(k = -1; k <= 1; k+= 1)
          point testcell = thiscell + vector(i,j,k);
          point pos = testcell;// + vector cellnoise(testcell) - 0.5;
          float dist = distance(pos,pp);
          if(dist < dist2nearest)
             dist2nearest = dist;
return dist2nearest;
cell_test(float Kd = 1,
                cellfreq = 5,
                shape_rad = 0.5,
                mindist = 10,
                maxdist = 15;
         string spacename = "shader")
color surfcolor = 1;
normal n = normalize(N);
normal nf = faceforward(n, I);
float d = dist2cell(P, spacename, cellfreq);
float rad = shape_rad;
if(d <= rad)
    Oi = Os;
    Oi = 0;
surfcolor = 1 - smoothstep(mindist, maxdist, length(I));
color diffusecolor = Kd * diffuse(nf);
Ci = Oi * Cs * surfcolor * diffusecolor;

The function, with the code shown in comments ie.

    point pos = testcell;// + vector cellnoise(testcell) - 0.5;

was used by the surface shader to assign transparency/opacity to a criss-crossed stack of poly-planes shown in figure 1. As can be seen the opaque spheres are aligned to the centers of the matrix of imaginary cells.

Figure 1

Figure 2

Figure 2 was rendered with cellnoise() activated ie.

    point pos = testcell + vector cellnoise(testcell) - 0.5;

As can be clearly seen in figure 2, cellnoise() has had the effect of jittering the centers of the lattice of cells. As a consequence the pattern of spheres has become irregular.

© 2002- Malcolm Kesson. All rights reserved.