The cri module is an alternative version of the ri module that uses the Python ctypes module to interface a renderer directly. The ctypes module is a foreign function library that is part of the standard Python libraries since Python 2.5 [1]. With previous versions of Python, the module has to be installed separately. The module can be used in combination with any renderer that implements the RenderMan API in a shared library. Using this module instead of the ri module has a number of advantages:
The disadvantage of using this module is that it depends on an external dynamic library that must implement the actual functionality. This means if you have not installed a renderer that ships with such a library you cannot use the module.
Before any RenderMan function can be used, a library has to be loaded using the loadRI() function. The returned module-like object can then be used just like the ri module.
Load a RenderMan library and return a module-like handle to it. libName is the name of a shared library that implements the RenderMan interface. The name can either be an absolute file name or just the name of the library (without suffix or “lib” prefix) in which case the function tries to find the library file itself. The return value is an object that can be used like a module, i.e. it contains all RenderMan functions, constants, etc. If libName is None or the empty string, the return value is just a reference to the ri module.
import cgkit.cri
ri = cgkit.cri.loadRI("3delight")
ri.RiBegin(ri.RI_NULL)
ri.RiWorldBegin()
ri.RiSurface("plastic")
ri.RiSphere(1,-1,1,360)
ri.RiWorldEnd()
ri.RiEnd()
The RenderMan function names can either be used with or without the “Ri” prefix. So the following is equivalent to the above:
ri.Begin(ri.RI_NULL)
ri.WorldBegin()
ri.Surface("plastic")
ri.Sphere(1,-1,1,360)
ri.WorldEnd()
ri.End()
The following table lists the library names for some renderers that are known to work with this module:
Renderer Library Name 3Delight 3delight Aqsis aqsislib / ri2rib Pixie ri PRMan (v14+) prman
Import the RenderMan names into the given namespace. ri is the module-like object that was returned by loadRI() and ns is a dictionary containing a module namespace (such as globals()) that will receive the “imported” symbols. Only the names with the “Ri” prefix will be available. Example:
ri = cgkit.cri.loadRI("3delight")
cgkit.cri.importRINames(ri, globals())
RiBegin(RI_NULL)
RiWorldBegin()
RiSurface("plastic")
RiSphere(1,-1,1,360)
RiWorldEnd()
RiEnd()
The following example renders three Koch curves that form sort of a “snowflake” shape. Each curve is created by a procedural which just uses a regular Python function as subdivide function. No RIB is generated by this example. — It is possible to create the same image using the generic ri module, but the procedural would have to be written as a separate Python script that is invoked using the “RunProgram” procedural. The code would actually be longer because you would have to encode/decode the parameters of the procedural as strings whereas this example directly passes vector objects around.
# Render a Koch snowflake as procedurals
import cgkit.cri
from cgkit.cgtypes import *
def bound(A, E):
"""Compute the bounding box of one segment."""
eps = 0.03
dv = E-A
n = vec3(-dv.y, dv.x, 0)
C = 0.5*(A+E) + 0.2887*n
xx = [A.x, C.x, E.x]
yy = [A.y, C.y, E.y]
bound = [min(xx)-eps, max(xx)+eps, min(yy)-eps, max(yy)+eps, -0.001, 0.001]
return bound
def subdiv(data, detail):
"""Subdivide function."""
A,E = data
dv = E-A
if dv.length()<0.005:
RiCurves(RI_LINEAR, [2], RI_NONPERIODIC, P=[A,E], constantwidth=0.003)
else:
t = 1.0/3
B = (1.0-t)*A + t*E
D = (1.0-t)*E + t*A
n = vec3(-dv.y, dv.x, 0)
C = 0.5*(A+E) + 0.2887*n
RiProcedural((A,B), bound(A,B), subdiv)
RiProcedural((B,C), bound(B,C), subdiv)
RiProcedural((C,D), bound(C,D), subdiv)
RiProcedural((D,E), bound(D,E), subdiv)
# Load the RenderMan API.
# Replace the library name with whatever renderer you want to use.
ri = cgkit.cri.loadRI("3delight")
cgkit.cri.importRINames(ri, globals())
RiBegin(RI_NULL)
RiFormat(1024,768,1)
RiDisplay("koch.tif", RI_FRAMEBUFFER, RI_RGB)
RiPixelSamples(3,3)
RiProjection(RI_ORTHOGRAPHIC)
RiScale(vec3(0.8))
RiTranslate(0,0.55,5)
RiWorldBegin()
RiSurface("constant")
RiColor((1,1,1))
RiPatch(RI_BILINEAR, P=[-2,2,1, 2,2,1, -2,-2,1, 2,-2,1])
RiColor((0,0,0))
RiProcedural((vec3(-1,0,0),vec3(1,0,0)), [-2,2, -2,2, -0.01,0.01], subdiv)
RiProcedural((vec3(0,-1.732,0),vec3(-1,0,0)), [-2,2, -2,2, -0.01,0.01], subdiv)
RiProcedural((vec3(1,0,0), vec3(0,-1.732,0)), [-2,2, -2,2, -0.01,0.01], subdiv)
RiWorldEnd()
RiEnd()
Running the above example produces this image:
Footnotes
[1] | Python 2.5 is embedded in Maya 2008/2009 and Houdini 9, whereas Maya 8.5 still uses Python 2.4. |