/*
GenSaturnRingsProc.cpp
A relatively simple example of a RiProcedural. For info see,
https://rmanwiki.pixar.com/display/REN22/Procedural+Primitives
In Cutter, make the DSO using the keyboard shortcut Alt+e or Control+e.
In Maya, select the RenderMan menu and choose,
Archive->Create Procedual Node
In Maya's attribute editor,
browse for the DSO ("DSO Name"),
enter this text into the "Data" field "200 0.2"
Assign a material, say, PxrConstant and render the scene. Image Tool
will display an image consisting of 200 small spheres.
M.A.Kesson
Jan 13 2019
*/
#include <ri.h>
#include <RixInterfaces.h>
#include <RiTypesHelper.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DEFAULT_RAD 1
#define DEFAULT_NUM 1
#define DEFAULT_INRAD 1
#define DEFAULT_OUTRAD 2
#define DEFAULT_H1 2
#define DEFAULT_H2 -1
#define DEFAULT_OFFSETX 0.1
#define DEFAULT_OFFSETZ 0.1
#define DEFAULT_DIS 1
// A RiProcedural must implement these functions. This is a fixed requirement.
extern "C"
{
PRMANEXPORT RtPointer ConvertParameters ( RtString paramStr );
PRMANEXPORT RtVoid Subdivide ( RtPointer data, RtFloat detail );
PRMANEXPORT RtVoid Free ( RtPointer data );
}
// A custom data structure for defining an arbitrary number of spheres
typedef struct {
RtFloat radius;
RtInt num;
RtFloat inner_radius;
RtFloat outer_radius;
RtFloat h1;
RtFloat h2;
RtFloat offsetx;
RtFloat offsetz;
RtFloat disintegration;
} SpheresData;
// Declare our utility functions...
RtFloat randBetween(RtFloat min, RtFloat max);
// ----------------------------------------------------
// A RiProcedural required function
// ----------------------------------------------------
// stderr strpbrk remainder
RtPointer ConvertParameters(RtString paramStr) {
// Allocate a block of memory to store one instance of our custom data structure.
SpheresData *dataPtr = (SpheresData*)malloc(sizeof(SpheresData));
// The user has forgotten to specify the number and size of the spheres in the
// RenderManProcedural's data text field - so we use our default values.
if(paramStr == NULL || strlen(paramStr) == 0) {
dataPtr->radius = DEFAULT_RAD;
dataPtr->num = DEFAULT_NUM;
dataPtr->num = DEFAULT_INRAD;
dataPtr->num = DEFAULT_OUTRAD;
dataPtr->num = DEFAULT_H1;
dataPtr->num = DEFAULT_H2;
dataPtr->num = DEFAULT_OFFSETX;
dataPtr->num = DEFAULT_OFFSETZ;
dataPtr->num = DEFAULT_DIS;
}
else
// We assume the input string consists of an integer and one float.
// For example, "200 0.2".
// The sscanf function reads the data from the parameter string, converts
// each item to the appropriate datatype and assigns their values to the
// appropriate "field" of our custom data structure.
sscanf(paramStr, "%d %f %f %f %f %f %f %f %f", &dataPtr->num, &dataPtr->radius,
&dataPtr->inner_radius, &dataPtr->outer_radius,
&dataPtr->h1, &dataPtr->h2,
&dataPtr->offsetx, &dataPtr->offsetz, &dataPtr->disintegration);
return (RtPointer)dataPtr;
}
// ----------------------------------------------------
// A RiProcedural required function
// ----------------------------------------------------
RtVoid Subdivide(RtPointer data, RtFloat detail) {
RtFloat radius = ((SpheresData*)data)->radius;
RtInt num = ((SpheresData*)data)->num;
RtFloat inner_radius = ((SpheresData*)data)->inner_radius;
RtFloat outer_radius = ((SpheresData*)data)->outer_radius;
RtFloat h1 = ((SpheresData*)data)->h1;
RtFloat h2 = ((SpheresData*)data)->h2;
RtFloat offsetx = ((SpheresData*)data)->offsetx;
RtFloat offsetz = ((SpheresData*)data)->offsetz;
RtFloat disintegration = ((SpheresData*)data)->disintegration;
srand(1);
// Output randomly located spheres
for(int n = 0; n < num; n++) {
RtFloat sr = randBetween(0.1,0.5) * radius;
RtFloat x = randBetween(-5,5);
RtFloat y = 0;
RtFloat z = randBetween(-5,5);
RtFloat r = randBetween(inner_radius,outer_radius);
RtFloat h = sin((x - disintegration)/3.14) * randBetween(h1,h2);
RtFloat offx = randBetween(0.8,offsetx);
RtFloat offz = randBetween(0.8,offsetz);
RtFloat dis = disintegration;
RtFloat color = sqrt(x * x + z * z);
RtVector3 vec(x,y,z);
//sin((x - disintegration)/3.14) *
vec.Normalize();
vec = vec * r;
if(x < dis)
{ RiTransformBegin();
RiTranslate(vec[0],vec[1],vec[2]);
// To assign a color to each sphere
RtColor cs[1] = { {r,r,r } } ;
RiSphere(sr, -sr, sr, 360, "constant color Cs", (RtPointer)cs, RI_NULL);
RiTransformEnd();
}
else if (x >= dis)
{ RiTransformBegin();
RiTranslate(vec[0]*offx,h,vec[2]*offz);
RtColor cs[1] = { { r,r,r } } ;
RiSphere(sr*0.8, -sr*0.8, sr*0.8, 360, "constant color Cs", (RtPointer)cs, RI_NULL);
RiTransformEnd();
}
}
}
// ----------------------------------------------------
// A RiProcedural required function
// ----------------------------------------------------
RtVoid Free(RtPointer data) {
free(data);
}
// ----------------------------------------------------
// Our utility functions begin here
// ----------------------------------------------------
RtFloat randBetween(RtFloat min, RtFloat max) {
return ((RtFloat)rand()/RAND_MAX) * (max - min) + min;
}
GenSaturnRingsProc.cpp
A relatively simple example of a RiProcedural. For info see,
https://rmanwiki.pixar.com/display/REN22/Procedural+Primitives
In Cutter, make the DSO using the keyboard shortcut Alt+e or Control+e.
In Maya, select the RenderMan menu and choose,
Archive->Create Procedual Node
In Maya's attribute editor,
browse for the DSO ("DSO Name"),
enter this text into the "Data" field "200 0.2"
Assign a material, say, PxrConstant and render the scene. Image Tool
will display an image consisting of 200 small spheres.
M.A.Kesson
Jan 13 2019
*/
#include <ri.h>
#include <RixInterfaces.h>
#include <RiTypesHelper.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DEFAULT_RAD 1
#define DEFAULT_NUM 1
#define DEFAULT_INRAD 1
#define DEFAULT_OUTRAD 2
#define DEFAULT_H1 2
#define DEFAULT_H2 -1
#define DEFAULT_OFFSETX 0.1
#define DEFAULT_OFFSETZ 0.1
#define DEFAULT_DIS 1
// A RiProcedural must implement these functions. This is a fixed requirement.
extern "C"
{
PRMANEXPORT RtPointer ConvertParameters ( RtString paramStr );
PRMANEXPORT RtVoid Subdivide ( RtPointer data, RtFloat detail );
PRMANEXPORT RtVoid Free ( RtPointer data );
}
// A custom data structure for defining an arbitrary number of spheres
typedef struct {
RtFloat radius;
RtInt num;
RtFloat inner_radius;
RtFloat outer_radius;
RtFloat h1;
RtFloat h2;
RtFloat offsetx;
RtFloat offsetz;
RtFloat disintegration;
} SpheresData;
// Declare our utility functions...
RtFloat randBetween(RtFloat min, RtFloat max);
// ----------------------------------------------------
// A RiProcedural required function
// ----------------------------------------------------
// stderr strpbrk remainder
RtPointer ConvertParameters(RtString paramStr) {
// Allocate a block of memory to store one instance of our custom data structure.
SpheresData *dataPtr = (SpheresData*)malloc(sizeof(SpheresData));
// The user has forgotten to specify the number and size of the spheres in the
// RenderManProcedural's data text field - so we use our default values.
if(paramStr == NULL || strlen(paramStr) == 0) {
dataPtr->radius = DEFAULT_RAD;
dataPtr->num = DEFAULT_NUM;
dataPtr->num = DEFAULT_INRAD;
dataPtr->num = DEFAULT_OUTRAD;
dataPtr->num = DEFAULT_H1;
dataPtr->num = DEFAULT_H2;
dataPtr->num = DEFAULT_OFFSETX;
dataPtr->num = DEFAULT_OFFSETZ;
dataPtr->num = DEFAULT_DIS;
}
else
// We assume the input string consists of an integer and one float.
// For example, "200 0.2".
// The sscanf function reads the data from the parameter string, converts
// each item to the appropriate datatype and assigns their values to the
// appropriate "field" of our custom data structure.
sscanf(paramStr, "%d %f %f %f %f %f %f %f %f", &dataPtr->num, &dataPtr->radius,
&dataPtr->inner_radius, &dataPtr->outer_radius,
&dataPtr->h1, &dataPtr->h2,
&dataPtr->offsetx, &dataPtr->offsetz, &dataPtr->disintegration);
return (RtPointer)dataPtr;
}
// ----------------------------------------------------
// A RiProcedural required function
// ----------------------------------------------------
RtVoid Subdivide(RtPointer data, RtFloat detail) {
RtFloat radius = ((SpheresData*)data)->radius;
RtInt num = ((SpheresData*)data)->num;
RtFloat inner_radius = ((SpheresData*)data)->inner_radius;
RtFloat outer_radius = ((SpheresData*)data)->outer_radius;
RtFloat h1 = ((SpheresData*)data)->h1;
RtFloat h2 = ((SpheresData*)data)->h2;
RtFloat offsetx = ((SpheresData*)data)->offsetx;
RtFloat offsetz = ((SpheresData*)data)->offsetz;
RtFloat disintegration = ((SpheresData*)data)->disintegration;
srand(1);
// Output randomly located spheres
for(int n = 0; n < num; n++) {
RtFloat sr = randBetween(0.1,0.5) * radius;
RtFloat x = randBetween(-5,5);
RtFloat y = 0;
RtFloat z = randBetween(-5,5);
RtFloat r = randBetween(inner_radius,outer_radius);
RtFloat h = sin((x - disintegration)/3.14) * randBetween(h1,h2);
RtFloat offx = randBetween(0.8,offsetx);
RtFloat offz = randBetween(0.8,offsetz);
RtFloat dis = disintegration;
RtFloat color = sqrt(x * x + z * z);
RtVector3 vec(x,y,z);
//sin((x - disintegration)/3.14) *
vec.Normalize();
vec = vec * r;
if(x < dis)
{ RiTransformBegin();
RiTranslate(vec[0],vec[1],vec[2]);
// To assign a color to each sphere
RtColor cs[1] = { {r,r,r } } ;
RiSphere(sr, -sr, sr, 360, "constant color Cs", (RtPointer)cs, RI_NULL);
RiTransformEnd();
}
else if (x >= dis)
{ RiTransformBegin();
RiTranslate(vec[0]*offx,h,vec[2]*offz);
RtColor cs[1] = { { r,r,r } } ;
RiSphere(sr*0.8, -sr*0.8, sr*0.8, 360, "constant color Cs", (RtPointer)cs, RI_NULL);
RiTransformEnd();
}
}
}
// ----------------------------------------------------
// A RiProcedural required function
// ----------------------------------------------------
RtVoid Free(RtPointer data) {
free(data);
}
// ----------------------------------------------------
// Our utility functions begin here
// ----------------------------------------------------
RtFloat randBetween(RtFloat min, RtFloat max) {
return ((RtFloat)rand()/RAND_MAX) * (max - min) + min;
}