The Python RenderMan binding is rather close to the C API, however there are some minor differences you should know about.
Types
In this binding typing is not as strict as in the C API. For compatibility reasons, the RenderMan types (RtBoolean, RtInt, RtFloat, etc.) do exist but they are just aliases to the corresponding built-in Python types and you never have to use them explicitly. In the ctypes-based cri module, the types refer to the respective ctypes types and you may want to use them occasionally to construct arrays.
Wherever the API expects vector types (RtPoint, RtMatrix, RtBound, RtBasis) you can use any value that can be interpreted as a sequence of the corresponding number of scalar values. These can be lists, tuples or your own class that can be used as a sequence.
It is also possible to use nested sequences instead of flat ones. For example, you can specify a matrix as a list of 16 values or as a list of four 4-tuples. The following two calls are identical:
RiConcatTransform([2,0,0,0, 0,2,0,0, 0,0,2,0, 0,0,0,1]) RiConcatTransform([[2,0,0,0], [0,2,0,0], [0,0,2,0], [0,0,0,1]])
Parameter lists
When passing parameter lists you have to know the following points:
RI_NULL. In Python
this is not necessary, the functions can determine the number of
arguments themselves. However, adding RI_NULL at the end of the list
will not generate an error. For example, if you are porting C code to
Python you don't have to change those calls. So the following two
calls are both valid:
RiSurface("plastic", "kd", 0.6, "ks", 0.4)
RiSurface("plastic", "kd", 0.6, "ks", 0.4, RI_NULL)
RI_P, RI_CS, ...) are
already pre-declared.
RiSurface("plastic", "kd", 0.6, "ks", 0.4)
Alternatively, you can use keyword arguments:
RiSurface("plastic", kd=0.6, ks=0.4)
But note that you can't use inline declarations using keyword
arguments. Instead you have to previously declare those variables
using RiDeclare. Also, you can't use keyword arguments if
the token is a reserved Python keyword (like the standard "from"
parameter). The third way to specify the parameter list is to provide
a dictionary including the token/value pairs:
RiSurface("plastic", {"kd":0.6, "ks":0.4})
This is useful if you generate the parameter list on the fly in your program.
Arrays
In the C API functions that take arrays as arguments usually take the length of the array as a parameter as well. This is not necessary in the Python binding. You only have to provide the array, the length can be determined by the function.
For example, in C you might write:
RtPoint points[4] = {0,1,0, 0,1,1, 0,0,1, 0,0,0};
RiPolygon(4, RI_P, (RtPointer)points, RI_NULL);
The number of points has to be specified explicitly. In Python however, this call could look like this:
points = [0,1,0, 0,1,1, 0,0,1, 0,0,0] RiPolygon(RI_P, points)
The functions that are affected by this rule are:
RiBlobby() RiColorSamples() RiCurves() RiGeneralPolygon() RiMotionBegin() RiPoints() RiPointsGeneralPolygons() RiPointsPolygons() RiPolygon() RiSubdivisionMesh() RiTransformPoints() RiTrimCurve()
When using the cri module it is particularly advantageous to pass arrays as ctypes arrays or numpy arrays. In this case, no data conversion is required which makes the function call considerably faster (particularly for large amounts of data).
# Creating a ctypes array of floats points = (12*RtFloat)(0,1,0, 0,1,1, 0,0,1, 0,0,0) # Creating a numpy array of floats points = numpy.array([0,1,0, 0,1,1, 0,0,1, 0,0,0], dtype=numpy.float32)
User defined functions
Some RenderMan functions may take user defined functions as input which will be used during rendering. When using the cri module to link to an actual RenderMan library you can use Python functions in addition to the standard functions. However, in the case of the generic (ri) module, you can only use the predefined standard functions.
Filter functions
It is not possible to use your own filter functions in combination with the ri module, you have to use one of the predefined filters:
Procedurals
It is not possible to use your own procedurals directly in the RIB generating program, you can only use one of the predefined procedural primitives:
However, this is not really a restriction since you always can use RiProcRunProgram to invoke your Python program that generates geometry.
Extended transformation functions
The transformation functions RiTranslate(), RiRotate(), RiScale() and RiSkew() have been extended in a way that is not part of the official spec. Each of these functions takes one or two vectors as input which usually are provided as 3 separate scalar values, like the axis of a rotation for example:
RiRotate(45, 0,0,1)
Now in this implementation you can choose to provide such vectors as sequences of 3 scalar values:
RiRotate(45, [0,0,1]) axis = vec3(0,0,1) RiRotate(45, axis)
Empty stubs
In the ri module, the function RiTransformPoints() always returns None and never transforms points (as the module just outputs RIB and does not maintain transformations matrices). In the cri module, on the other hand, the function is available and can be used to transform points.