- New variable types

- Arrays

- New texture mapping tokens

- New built-in functions

- Message passing

- Scoping changes

The 3.1 specification of the RenderMan Interface defined only one type of geometric triple: point. In affine geometry, points and vectors behave differently. For example, points may be translated but vectors are immune to translation.

In addition to point, RenderDotC defines vector and normal types. All three have x, y, and z components. They only behave differently when being automatically transformed from one coordinate system to another. Vectors transform the same was as points except translation is ignored. Normals are transformed such that they remain perpendicular to a plane undergoing the same transformation. More specifically, normals are mutiplied by the inverse transpose of the transformation matrix.

Shader parameters may be declared point, vector or normal using RiDeclare. When triples are passed to the shader, they are automatically transformed to the current space. The details of this transformation depend upon the type.

In addition, triples may be implicitly transformed from within the shader. For example:

This projects the vector (0, 1, 0) from "shader" space to "current" space.vector up = vector "shader" (0, 1, 0);

To explicitly transform a point, vector, or normal from one space to another, use the transform, vtransform, or ntransform function, respectively. The vtransform and ntransform functions are shading language extensions documented below.

**Matrices**

The matrix data type represents a 4x4 array of floating point numbers. Such matrices are often called "homogeneous" or "affine" transformations because multiplying a 3D point or vector by a 4x4 matrix performs an affine transformation (the fourth row is necessary for translating points). This is the same type of matrix that RenderDotC uses internally to implement coordinate systems, transform(), etc.

In RIB, a matrix is declared like this:

Varying and vertex matrices are also allowed. Matrices may be passed from RIB to shaders in the token-value lists of shaders or primitives:Declare "mshader" "uniform matrix"

Matrices passed to shaders are automatically projected from "shader" to "current" space, while matrices passed to primitives undergo the "object" to "current" transformation.Surface "printall" "mshader" [1 0 0 0 0 1 0 0 0 0 1 0 10 20 30 1]Points "P" [0 0 0] "mobject" [1 0 0 0 0 1 0 0 0 0 1 0 10 20 30 1]

Within the shading language, matrices may be explicitly initialized with a list of 16 values:

This syntax is similar to the way points are initialized. Like points, matrix initializers take an optional coordinate system:uniform matrix mscalexy = (2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);

The latter syntax prepends the "current" to "space" transformation (where "space" is "shader" in the example).uniform matrix mscalexy = matrix "shader" (2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);

Casting from a float to a matrix results in a matrix with all zeros except on the diagonal, where all four values equal the original float. This is often used to create the identity matrix. The following two lines are equivalent:

The equality and inequality operators are defined on matrices:uniform matrix identity = 1;uniform matrix identity = (1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);

These operators compare the matrices component-by-component.if (m1 == m2) ...if (m1 != m2) ...

Matrices may be multiplied or divided:

Dividing by a matrix is equivalent to multiplying the left hand matrix by the inverse of the right hand matrix. If the right hand matrix is uninvertible, and error message will be printed and the result of the division expression will be the left hand matrix.m3 = m1 * m2;m3 = m1 / m2;

The following builtin functions take matrix arguments:

They are described in detail below.float determinant(matrix m)matrix inverse(matrix m)point transform(matrix m, point p)vector vtransform(matrix m, vector v)normal ntransform(matrix m, normal n)point transform(string space, matrix m, point p)vector vtransform(string space, matrix m, vector n)normal ntransform(string space, matrix m, normal n)matrix translate(matrix m, point t)matrix rotate(matrix m, float angle, vector axis)matrix scale(matrix m, point s)float comp(matrix m; float row, column)void setcomp(matrix m; float row, column; float newvalue)printf("%m", m1)

` uniform string months[12] = {"january", "february",
"march", ...};`

An array element may be used in any exression where a single variable of the same base type is allowed. If an element of an array is used as an actual parameter to a function which returns a value in that parameter, this sets that element to the return value. In other words, array elements are call-by-reference, just like other function arguments in RenderMan shading language.

If an array of strings is used as the first argument to texture(), then it's ambiguous whether square brackets indicate an array subscript or a channel number. If two sets of square brackets are present, the first is the array subscript and the second is the channel number. If only one set of square brackets appear, then they are interpreted as an array subscript. The channel number will default to 0 in this case.

The spline function has been extended to allow
control vertices to be passed as arrays.

SL: | Defaults |

texture(mapname, "width", x) | 1.0 |

texture(mapname, "fill", x) | 0.0 |

texture(mapname, "lerp", b) | 1.0 |

texture(mapname, "filter", "s") | "box" |

texture(mapname, "blur", x) | 0.0 |

texture(mapname, "sblur", x) | 0.0 |

texture(mapname, "tblur", x) | 0.0 |

shadow(mapname, "bias", x) | (bias0 + bias1) / 2 |

shadow(map1,map2,map3) | - none - |

shadow(mapname, "source", p1, p2, p3, p4) | P |

shadow(mapname, "gapbias", x) | (bias0 + bias1) * 5 |

` C = texture("map.tex"[0], "fill", 0);`
` A = texture("map.tex"[3], "fill", 1);`

If the texture map has an alpha channel it will be used. Otherwise, it will default to opaque (1).

The "fill" token is not recognized by the shadow() function.

Note that this flag may be overridden by the enable lerp option.

The "lerp" token is not recognized by the shadow() function.

Note that this flag may be overridden by the enable gaussian option.

The shadow() function honors only the "box" and "gaussian" filters.

` totalds = swidth * ds + sblur`
` totaldt = twidth * dt + tblur`

where ds and dt are the actual dimensions of the area being textured in texture coordinates. Values for sblur and tblur are usually small, such as 0.001, because 1.0 covers the entire width of the texture.

The "blur" token may be used to conveniently set "sblur" and "tblur" to the same value.

The "bias" token is only honored by the shadow() function.

Consecutive pixels in a shadow map whose values differ by gapbias or less are inferred to be generated by the same object. For more information, see the tutorial on creating soft shadows.

These are corrolaries to the original transform() functions. Where transform() works correctly on points, vtransform is for vectors and ntransform is for normals. Vectors and normals transform differently than points. Care should be taken to choose the form that is correct for the application.vector vtransform(string tospace; vector v)vector vtransform(string fromspace, tospace; vector v)normal ntransform(string tospace; normal n)normal ntransform(string fromspace, tospace; normal n)

If fromspace is not specified, "current" is the default.

These explicitly multiply a point, vector or normal by a matrix. Again, vectors and normals transform differently than points.point transform(matrix m, point p)vector vtransform(matrix m, vector v)normal ntransform(matrix m, normal n)

This form first transforms the point, vector, or normal from "space" to "current" and then multiply by the matrix.point transform(string space, matrix m, point p)vector vtransform(string space, matrix m, vector v)normal ntransform(string space, matrix m, normal n)

Returns the euclidean distance from point Q to the nearest point on the line segment from P0 to P1. Note that if the point nearest Q on the infinite line through P0 and P1 does not lie between P0 and P1, it will be clamped to that range before the distance is taken. In other words, ptlined() does not return the distance between Q and an infinite line.float ptlined(point P0, point P1, point Q)

Returns a pseudorandom value that depends upon the floor of all its arguments. The random values are uniformly distributed over the range from 0 to 1. The results are repeatable: given the same input (or input similar enough that the floor of all arguments is identical) cellnoise will return the same value.float cellnoise(float x)float cellnoise(float s, float t)float cellnoise(point pt)float cellnoise(point pt, float t)point cellnoise(float x)point cellnoise(float s, float t)point cellnoise(point pt)point cellnoise(point pt, float t)color cellnoise(float x)color cellnoise(float s, float t)color cellnoise(point pt)color cellnoise(point pt, float t)

The min and max functions can now take two or more arguments. The min/max of all arguments is returned.float min(float a, b, ...)point min(point a, b, ...)point min(vector a, b, ...)point min(normal a, b, ...)color min(color a, b, ...)float max(float a, b, ...)point max(point a, b, ...)point max(vector a, b, ...)point max(normal a, b, ...)color max(color a, b, ...)

The clamp and mix functions now operate on all of the scalar data types. Those with more than one component are computed separately on each component.float clamp(float a, min, max)point clamp(point a, min, max)point clamp(vector a, min, max)point clamp(normal a, min, max)color clamp(color a, min, max)float mix(float fg, bg; float value)point mix(point fg, bg; float value)point mix(vector fg, bg; float value)point mix(normal fg, bg; float value)color mix(color fg, bg; float value)

Four dimensional noise is now supported. The return value is repeatable and depends on all four input values. A common application is to use time as the fourth dimension.float noise(point pt, float t)color noise(point pt, float t)point noise(point pt, float t)

Periodic noise behaves the same as regular noise but with the additional property that the return value repeats itself with the frequency given by the period argument. In other words, pnoise(v, period) == pnoise(v + period, period) For best results, all periods should be specified with integers.float pnoise(float v, uniform float period)float pnoise(float u, float v, uniform float uperiod, uniform float vperiod)float pnoise(point pt, uniform point period)float pnoise(point pt, float t, uniform point pperiod, uniform float tperiod)point pnoise(float v, uniform float period)point pnoise(float u, float v, uniform float uperiod, uniform float vperiod)point pnoise(point pt, uniform point period)point pnoise(point pt, float t, uniform point pperiod, uniform float tperiod)color pnoise(float v, uniform float period)color pnoise(float u, float v, uniform float uperiod, uniform float vperiod)color pnoise(point pt, uniform point period)color pnoise(point pt, float t, uniform point pperiod, uniform float tperiod)

- A character matches itself, unless it is a special character (metachar): . \ [ ] * + ^ $
- A period "." matches any character.
- A backslash "\" matches the character following it, except when followed by a left or right round bracket, a digit 1 to 9 or a left or right angle bracket (see [7], [8] and [9]). It is used as an escape character for all other meta-characters, and itself. When used in a set ([4]), it is treated as an ordinary character.
- A set of characters enclosed in square brackets "[" and "]" matches one of the characters in the set. If the first character in the set is "^", it matches a character NOT in the set, i.e. complements the set. A shorthand S-E is used to specify a set of characters S upto E, inclusive. The special characters "]" and "-" have no special meaning if they appear as the first chars in the set. For example:
- [a-z] matches any lowercase alpha
- [^]-] matches any char except ] and -
- [^A-Z] matches any char except uppercase alpha
- [a-zA-Z] matches any alpha.
- Any regular expression form [1] to [4], followed by an asterisk "*" matches zero or more matches of that form.
- A plus sign "+" behaves the same as [5], except it matches one or more.
- A regular expression in the form [1] to [10], enclosed by "\(" and "\)" matches the regular expression but also creates a set of tags, used for [8] and for pattern substution. The tagged forms are numbered starting from 1.
- A backslash "\" followed by a digit 1 to 9 matches whatever a previously tagged regular expression ([7]) matched.
- A regular expression starting with a "\<" construct and/or ending with a "\>" construct, restricts the pattern matching to the beginning of a word, and/or the end of a word. A word is defined to be a character string beginning and/or ending with the characters A-Z a-z 0-9 and _. It must also be preceded and/or followed by any character outside those mentioned.
- A composite regular expression xy where x and y are in the form [1] to [10] matches the longest match of x followed by a match for y.
- A regular expression starting with a caret "^" character and/or ending with a dollar "$" character, restricts the pattern matching to the beginning of the line, or the end of line. Elsewhere in the pattern, ^ and $ are treated as ordinary characters.

Returns the determinant of matrix m.float determinant(matrix m)

Inverts a matrix. This is equivalent to (1 / m). If the matrix is singular (i.e. uninvertible), an error message will be printed and the function will return the identity matrix.matrix inverse(matrix m)

These functions post-multiply m by a translation, rotation, or scale matrix, respectively. Note that the rotation angle is in radians.matrix translate(matrix m, point t)matrix rotate(matrix m, float angle, vector axis)matrix scale(matrix m, point s)

These functions get and set individual components of matrices.float comp(matrix m; float row, column)void setcomp(matrix m; float row, column; float newvalue)

The printf function has been augmented to handle matrices. Use the "%m" conversion specifier.printf("%m", m1)

In the first form, the range is automatically computed as abs(Du(s1)*du) + abs(Dv(s1)*dv), resulting in a smooth step over the size of one surface element. The usual warning about not using "area operators" inside of varying conditionals apply to the first form of filterstep. In the second form, the range equals abs(s2 - s1). This form may be used inside varying conditionals.

The parameter list may contain token-value pairs. To specify which filter kernel to use, include the token "filter" followed by "box", "triangle", "catmull-rom", or "gaussian". For example, to select the Gaussian filter kernel:

The default filter is "catmull-rom".filterstep(edge, s1, "filter", "gaussian");

To adjust the amount of overfilter, use the token "width" (or "swidth" synonymously) followed by a floating point number indicating a factor to multiply the filter width by. For example, to double the filter size:

Each filter kernel has an inherent width of support. Outside of that area of support, filterstep returns either 0 or 1. For reference:filterstep(edge, s1, "width", 2.0);

Increasing the difference between s0 and s1 or increasing the amout of overfilter with the "width" token will increase the area of support for all of the filter kernels. In other words, the total support width of a filter is the product of its inherent width, the overfilter factor, and the range (either abs(Du(s1)*du) + abs(Dv(s1)*dv) or abs(s2 - s1)).filterstep(x, 0, 1, "filter", "box")is defined over the range x = -0.5 to 0.5 (width 1).filterstep(x, 0, 1, "filter", "triangle")is defined over the range x = -1 to 1 (width 2).filterstep(x, 0, 1, "filter", "catmull-rom")is defined over the range x = -2 to 2 (width 4).filterstep(x, 0, 1, "filter", "gaussian")is defined over the range x =-1.5 to 1.5 (width 3).

All of the filters used by filterstep() change their shape to match the width. Contrast that with the pixel filters RiCatmullRomFilter() and RiSincFilter() which retain their shape but are merely windowed by xwidth and ywidth.

The difference between this form and the standard one from the RenderMan spec is that the basis of the spline may be specified. The old form is still supported with the implied basis "catmull-rom". With the new form, the basis may be "catmull-rom", "bezier", "hermite", "linear", or "bspline" (note: not "b-spline"). The "linear" basis needs some further explanation. The first and last control vertices are completely ignored. Points on the spline are linearly interpolated between the nearest two control vertices.

The control vertices may optionally be passed to spline() in a shading language array of four or more values. If the basis is omitted, it defaults to "catmull-rom".float spline([string basis;] float v; float f[])color spline([string basis;] float v, color c[])point spline([string basis;] float v, point p[])

RenderMan attributes can vary from one primitive to the next. The data returned by attribute() is within the context of the primitive being shaded. Note that "displacementbound:coordinatesystem" always returns "camera", and that "displacementbound:sphere" returns the bound in camera coordinates.float attribute(string, variable)

value of string variable type RenderMan Interface call "ShadingRate" uniform float ShadingRate "Matte" uniform float Matte "GeometricApproximation:motionfactor" uniform float GeometricApproximation "motionfactor" "Sides" uniform float Sides "displacementbound:sphere" uniform float Attribute "displacementbound" "sphere" "displacementbound:coordinatesystem" uniform string Attribute "displacementbound" "coordinatesystem" "identifier:name" uniform string Attribute "identifier" "name"

float option(string, variable)

value of string variable type RenderMan Interface call "Format" uniform float[3] RiFormat "DepthOfField" uniform float[3] RiDepthOfField "Shutter" uniform float[2] RiShutter "Clipping" uniform float[2] RiClipping

float textureinfo(filename, string, variable)

value of string variable type description of data returned "resolution" uniform float[2] x and y dimensions of highest resolution subimage in texture map "type" uniform string "texture", "shadow" or "environment" "channels" uniform float number of channels in texture map (e.g. "rgb" is 3 channels) "viewingmatrix" uniform matrix world-to-light transformation matrix in a shadow map "projectionmatrix" uniform matrix world-to-NDC transformation matrix in a shadow map

float rendererinfo(string, variable)

value of string variable type description of data returned "renderer" uniform string name of renderer "version" uniform float [4] the renderer version as four separate numbers "versionstring" uniform string version of the renderer as a string

` float displacement(string varname; {float|point|color|string}
value)`
` float lightsource(string varname; {float|point|color|string}
value)`
` float surface(string varname; {float|point|color|string}
value)`
` float atmosphere(string varname; {float|point|color|string}
value)`

The name of the function matches the type of shader from which you wish
to receive a message. The first argument is a string containing the
name of a variable that may be exported from the sending shader.
If the sending shader exists, and it has an output
parameter *varname*, and it's the same type as *value, *then
the value of the output parameter is stored in *value* and the function
returns 1. Otherwise, the function returns 0 and *value* is
left unchanged. If the parameter is uniform and *value* is varying,
then it is promoted. The lightsource() function may only be called
within an illuminance loop.

It makes more sense to pass messages "downstream" to shaders that have not yet been evaluated. For a given piece of geometry, the order of evaluation of shaders in RenderDotC is displacement, all of the lights, surface, and atmosphere. Attempting to pass messages "upstream" will yield the default value from the parameter initializer.

` displacement waves(float ampl = 1;`
`
output varying vector displaced = 0;)`

As a convenience, all parameters whose names begin with a double underscore are automatically flagged as output.

` lightsource blacklight(uniform string __category
= "uv,black")`

This string variable may contain one or more group names, separated by commas, indicating that this light is a member of each of these groups. These names are defined by the user. The renderer does not predefine any category names.

The benefit of declaring a light to be a member of a category is that other shaders may selectively ignore whole categories of lights. The illuminance() function now takes an optional first argument which is a string:

` illuminance("black", P)`

In the example above, the illuminance loop will only be executed for lights that belong to the category "black". Note that the category argument to illuminance() may not be a comma-delimited list but rather a single category.

The category string may optionally be prefixed with a minus sign:

` illuminance("-black", P)`

This causes illuminance() to explicitly exclude a category and accept
all others.

The output keyword may be used in shader parameter lists for the purpose of sending messages.

Variable declarations beginning with extern are completely ignored.
This keyword exists only for compatibility with other renderers.
In RenderDotC, globals and variables declared in outer scopes are always
available to user-defined functions, provided that they are not hidden
by local variables of the same name.

Dot C Software, Inc., 182 Kuuhale St., Kailua, HI 96734

(808) 262-6715 (voice) (808) 261-2039 (fax)

The RenderMan® Interface Procedure and RIB Protocol are:

Copyright © 1988, 1989, Pixar. All rights reserved.

RenderMan® is a registered trademark of Pixar.