9.5 Writing Procedural Primitives
This section is meant to provide examples on how to write simple procedural primitives for 3Delight. For more complete documentation about procedural primitives and the interface to them, refer to the RenderMan Interface Specification available at https://renderman.pixar.com/products/rispec/index.htm.
| 9.5.1 The RunProgram Procedural Primitive | ||
| 9.5.2 The DynamicLoad Procedural Primitive |
9.5.1 The RunProgram Procedural Primitive
This example shows how to write a procedural primitive in the form of an external program which generates RIB. It can be invoked in a RIB stream as such:
Procedural "RunProgram" ["sphere" "0 0.5 1"] [-1 1 -1 1 -1 1]
The three floats it receives as parameters represent a color, as expected by the program. The program itself outputs a sphere of that color. This example also shows how to generate a RIB using `lib3delight'. Note that on Windows, 3Delight searches for `sphere.exe' if it doesn't find `sphere' in its procedural search path.
Note that a poorly written program (especially one which fails to output the \377 delimiter) may easily hang the renderer. Great care was taken in 3Delight to check for the most common errors but there are still some which are not caught. It is also important that your program be written to accept multiple requests.
#include <stdio.h>
#include <stdlib.h>
#include "ri.h"
int main(int argc, char **argv)
{
char buf[256];
/*
You can still use the standard error output to diagnose your program.
This allows you to see that your program is started only once even if it
is invoked several times in a frame.
*/
fprintf(stderr, "diagnostic: sphere program started.\n");
/*
Requests from the renderer to the program are passed on the standard
input. Each request is written on a single line. The detail level required
is written first, followed by the arguments passed by the user in the RIB.
The two are separated by a single space.
*/
while (fgets(buf, 256, stdin) != NULL)
{
RtFloat detail;
RtColor color = {1.0f, 1.0f, 1.0f};
sscanf(buf, "%g %g %g %g", &detail, &color[0], &color[1], &color[2]);
/*
Calling RiBegin with a file name as a parameter causes the commands
to be output as RIB to that file when using lib3delight. Using
"stdout" or "stderr" will output the RIB to the standard output or
error respectively.
It is important to call RiBegin()/RiEnd() inside the loop (for each
request) to ensure that the output is received properly by the
renderer.
*/
RiBegin("stdout");
RiColor(&color[0]);
RiSphere(1.0f, -1.0f, 1.0f, 360.0f, RI_NULL);
/*
Outputting a single 0xFF character (377 in octal) is the method to
signal the renderer that the program has finished processing this
request. This can also be done manually if you choose not to use the
library to output your RIB.
*/
RiArchiveRecord(RI_VERBATIM, "\377");
RiEnd();
}
fprintf(stderr, "diagnostic: sphere program is about to end.\n");
return 0;
}
This example can be compiled with the following commands:
- Linux
g++ -o sphere -O3 -I$DELIGHT/include/ -L$DELIGHT/lib/ sphere.cpp -l3delight- Mac OS X
g++ -o sphere -O3 -I$DELIGHT/include/ -L$DELIGHT/lib/ sphere.cpp -l3delight- IRIX
CC -o sphere -O3 -n32 -TARG:isa=mips4 -TARG:processor=r10k -I$DELIGHT/include/ -L$DELIGHT/lib/ sphere.cpp -l3delight- Windows
CL /Ox /I"%DELIGHT%\include" sphere.cpp "%DELIGHT%\lib\3Delight.lib"
9.5.2 The DynamicLoad Procedural Primitive
This example shows how to write a procedural primitive in the form of a DSO. It is special in that it calls itself a number of times to create a Menger's Sponge(70). It can be invoked in a RIB stream as such:
Procedural "DynamicLoad" ["sponge" "3"] [-1 1 -1 1 -1 1]
The single parameter it takes is the maximal recursion depth. It also makes use of the `detailsize' parameter of the subdivision routine to avoid outputting too much detail. Note that 3Delight attempts to find `sponge.so' (or `sponge.dll' on Windows) and then `sponge' in the procedural search path. This allows you not to specify the extension.
#include <stdlib.h>
#include <stdio.h>
#include "ri.h"
#if defined(_WIN32)
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Declarations */
RtPointer DLLEXPORT ConvertParameters(RtString paramstr);
RtVoid DLLEXPORT Subdivide(RtPointer data, float detail);
RtVoid DLLEXPORT Free(RtPointer data);
RtPointer DLLEXPORT ConvertParameters(RtString paramstr)
{
int* depth = (int*) malloc(sizeof(int));
*depth = 3; /* decent default value */
sscanf(paramstr, "%d", depth);
return depth;
}
RtVoid DLLEXPORT Subdivide(RtPointer blinddata, RtFloat detailsize)
{
int depth = *(int*) blinddata;
/* Simple usage of detailsize to avoid drawing too much detail */
if (depth <= 0 || detailsize <= 5.0f)
{
/* Draw a cube */
RtInt nverts[] = {4, 4, 4, 4, 4, 4};
RtInt verts[] = {
3, 7, 6, 2, /* top face */
5, 1, 0, 4, /* bottom face */
7, 3, 1, 5, /* back face */
3, 2, 0, 1, /* left face */
6, 7, 5, 4, /* right face */
2, 6, 4, 0}; /* front face */
RtFloat points[] = {
-1, -1, -1, -1, -1, 1,
-1, 1, -1, -1, 1, 1,
1, -1, -1, 1, -1, 1,
1, 1, -1, 1, 1, 1};
RiPointsPolygons(
(RtInt)6, nverts, verts, RI_P, (RtPointer)points, RI_NULL);
} else {
/* Recursive call, reduce depth and scale the object by 1/3 */
RtBound bound = {-1, 1, -1, 1, -1, 1};
int* newDepth;
unsigned x,y,z;
RiScale(1.0/3.0, 1.0/3.0, 1.0/3.0);
for (x = 0; x < 3; ++x)
for (y = 0; y < 3; ++y)
for (z = 0; z < 3; ++z)
if (x % 2 + y % 2 + z % 2 < 2)
{
RiTransformBegin();
RiTranslate(
x * 2.0 - 2.0,
y * 2.0 - 2.0,
z * 2.0 - 2.0);
newDepth = (int*) malloc(sizeof(int));
*newDepth = depth - 1;
/* We could make the recursive call using
RiProcDynamicLoad but that would be more complex and
slightly less efficient */
RiProcedural(newDepth, bound, Subdivide, Free);
RiTransformEnd();
}
}
}
RtVoid DLLEXPORT Free(RtPointer blinddata)
{
free(blinddata);
}
#ifdef __cplusplus
}
#endif
This example can be compiled with the following commands:
- Linux
- gcc -o sponge.so -O3 -I
$DELIGHT/include/ -shared sponge.c - Mac OS X
- gcc -dynamiclib -o sponge.so -O3 -I
$DELIGHT/include/ -L$DELIGHT/lib/ sponge.c -l3delight - IRIX
- CC -o sponge.so -O3 -n32 -TARG:isa=mips4 -TARG:processor=r10k -I
$DELIGHT/include/ -shared sponge.c - Windows
- CL /Ox /LD /I"%DELIGHT%\include" sponge.c "%DELIGHT%\lib\3Delight.lib"
3Delight 8.5. Copyright 2000-2009 The 3Delight Team. All Rights Reserved.