1
//-------------------------------------------
2
// The standard renderman quadric primitives
3
//-------------------------------------------
11
//------------------------------------------------------------------------------
12
// functions used for bound calculation
14
// 2D polar to cartesian
15
inline Point3 polar2D(float radius, float theta)
17
return Point3(cosf(theta)*radius, sinf(theta)*radius, 0);
20
// parametric 2D bound calc.
21
inline Bound bounds2DSweepL(float rmin, float rmax, float tmin, float tmax)
24
b.include(polar2D(rmin, tmin));
25
b.include(polar2D(rmax, tmin));
26
b.include(polar2D(rmin, tmax));
27
b.include(polar2D(rmax, tmax));
28
if ((tmin < (float)M_PI_2) && (tmax > (float)M_PI_2)) b.include(polar2D(rmax, (float)M_PI_2));
29
if ((tmin < (float)M_PI) && (tmax > (float)M_PI)) b.include(polar2D(rmax, (float)M_PI));
30
if ((tmin < float(M_PI+M_PI_2)) && (tmax > float(M_PI+M_PI_2))) b.include(polar2D(rmax, float(M_PI+M_PI_2)));
35
inline Bound bounds2DSweepR(float r, float phimin, float phimax)
38
b.include(polar2D(r, phimin));
39
b.include(polar2D(r, phimax));
40
for (int i=-3; i<4; i++) {
41
const float ip = i*(float)M_PI_2;
42
if ((phimin < ip) && (phimax > ip)) b.include(polar2D(r, ip));
47
// only used by hyperboloid
48
inline Bound bounds2DSweepP(const Point3 &P, float tmin, float tmax)
51
const float r = sqrt(P.x*P.x + P.y*P.y);
52
const float delta = ((P.x==0.f) && (P.y==0.f)) ? 0.f : atan2f(P.y, P.x);
55
b.include(polar2D(r, tmin));
56
b.include(polar2D(r, tmax));
58
for (int i=-1; i<6; i++) {
59
const float ip = i*(float)M_PI_2;
60
if ((tmin < ip) && (tmax > ip)) b.include(polar2D(r, ip));
65
//------------------------------------------------------------------------------
66
// Quadric primitives (including quartic torus)
67
// all angle values that specify the extent are clamped to (0, 360) range
69
//------------------------------------------------------------------------------
72
Disk::Disk():height(1), radius(1), thetamax(2.f*(float)M_PI)
76
Disk::Disk(float _height, float _radius, float _thetamax,
77
RtInt n, RtToken tokens[], RtPointer parms[])
78
: height(_height), radius(_radius)
80
radians(thetamax, CLAMP(ABS(_thetamax), 0.f, 360.f));
81
Primitive::initPrimVars(n, tokens, parms, 1, 4, 4, 4);
86
Bound b = bounds2DSweepL(radius*(1.f-vmax), radius*(1.f-vmin), umin*thetamax, umax*thetamax);
87
b.minmax[0].z = b.minmax[1].z = height;
93
void Disk::eval(float u, float v, RtPoint P, RtVector dPdu, RtVector dPdv) const
95
const float t = u*thetamax;
96
const float sint = sinf(t), cost = cosf(t);
97
float r = radius*(1.f - v);
98
P[0] = r*cost, P[1] = r*sint, P[2] = height;
101
dPdu[0] = -r*sint, dPdu[1] = r*cost, dPdu[2] = 0;
102
dPdv[0] = -radius*cost, dPdv[1] = -radius*sint, dPdv[2] = 0;
106
//------------------------------------------------------------------------------
107
// Sphere, uses reference counted data to test if that would improve
108
// memory usage, but probably can be removed.
109
// Probably doesn't help much, unless the sphere is split often.
111
Sphere::Sphere(float _radius, float _zmin, float _zmax, float _thetamax,
112
RtInt n, RtToken tokens[], RtPointer parms[])
114
spdata = new spData();
115
spdata->radius = _radius;
116
// keep zmin/zmax within +/- radius range
117
spdata->zmin = MAX2(-spdata->radius, _zmin);
118
spdata->zmax = MIN2(spdata->radius, _zmax);
119
if (spdata->radius<=0.f) spdata->radius = 1e-5f;
120
radians(spdata->thetamax, CLAMP(ABS(_thetamax), 0.f, 360.f));
121
spdata->alphamin = asinf(CLAMP(spdata->zmin/spdata->radius, -1.f, 1.f));
122
spdata->alphadelta = asinf(CLAMP(spdata->zmax/spdata->radius, -1.f, 1.f)) - spdata->alphamin;
123
Primitive::initPrimVars(n, tokens, parms, 1, 4, 4, 4);
128
if (spdata && (--spdata->refc == 0)) {
134
Bound Sphere::bound()
136
const float avmin = spdata->alphamin + vmin*spdata->alphadelta;
137
const float avmax = spdata->alphamin + vmax*spdata->alphadelta;
138
const float rvmin = cosf(avmin)*spdata->radius;
139
const float rvmax = cosf(avmax)*spdata->radius;
140
const float rmin = MIN2(rvmin, rvmax);
141
const float rmax = ((avmin<0.f) && (avmax>0.f)) ? spdata->radius : (MAX2(rvmin, rvmax));
142
Bound b = bounds2DSweepL(rmin, rmax, umin*spdata->thetamax, umax*spdata->thetamax);
143
b.minmax[0].z = sinf(avmin)*spdata->radius;
144
b.minmax[1].z = sinf(avmax)*spdata->radius;
150
void Sphere::eval(float u, float v, RtPoint P, RtVector dPdu, RtVector dPdv) const
152
// correction for singularity at poles (only needed for correct normals, probably precision issue, get correct results for 0,0 in py)
153
u = MAX2(1e-6f, u), v = MAX2(1e-6f, v);
154
const float alpha = spdata->alphamin + v*spdata->alphadelta;
155
const float car = cosf(alpha)*spdata->radius, t = u*spdata->thetamax;
156
const float sint = sinf(t), cost = cosf(t), sina = sinf(alpha);
157
P[0] = cost*car, P[1] = sint*car, P[2] = sina*spdata->radius;
159
dPdu[0] = -spdata->thetamax*sint*car, dPdu[1] = spdata->thetamax*cost*car, dPdu[2] = 0;
160
const float ar = spdata->alphadelta*spdata->radius;
161
const float sar = -sina*ar;
162
dPdv[0] = cost*sar, dPdv[1] = sint*sar, dPdv[2] = cosf(alpha)*ar;
166
Parametric* Sphere::duplicateSelf()
168
Sphere* sp = new Sphere(*this);
169
if (spdata) spdata->refc++;
173
//------------------------------------------------------------------------------
176
Cylinder::Cylinder(): radius(1), zmin(-1), zmax(1), thetamax(2.f*(float)M_PI)
180
Cylinder::Cylinder(float _radius, float _zmin, float _zmax, float _thetamax,
181
RtInt n, RtToken tokens[], RtPointer parms[])
182
: radius(_radius), zmin(_zmin), zmax(_zmax)
184
radians(thetamax, CLAMP(ABS(_thetamax), 0.f, 360.f));
185
Primitive::initPrimVars(n, tokens, parms, 1, 4, 4, 4);
188
Bound Cylinder::bound()
190
Bound b = bounds2DSweepL(radius, radius, umin*thetamax, umax*thetamax);
191
b.minmax[0].z = zmin + vmin*(zmax-zmin);
192
b.minmax[1].z = zmin + vmax*(zmax-zmin);
198
void Cylinder::eval(float u, float v, RtPoint P, RtVector dPdu, RtVector dPdv) const
200
const float t = u*thetamax;
201
const float sint = sinf(t), cost = cosf(t);
203
const float tr = thetamax*radius;
204
dPdu[0] = -sint*tr, dPdu[1] = cost*tr;
205
dPdu[2] = dPdv[0] = dPdv[1] = 0, dPdv[2] = zmax - zmin;
206
P[0] = cost*radius, P[1] = sint*radius, P[2] = zmin + v*dPdv[2];
209
P[0] = cost*radius, P[1] = sint*radius, P[2] = zmin + v*(zmax - zmin);
212
//------------------------------------------------------------------------------
215
Cone::Cone(): height(1), radius(1), thetamax(2.f*(float)M_PI)
219
Cone::Cone(float _height, float _radius, float _thetamax,
220
RtInt n, RtToken tokens[], RtPointer parms[])
221
: height(_height), radius(_radius)
223
radians(thetamax, CLAMP(ABS(_thetamax), 0.f, 360.f));
224
Primitive::initPrimVars(n, tokens, parms, 1, 4, 4, 4);
229
Bound b = bounds2DSweepL(radius*(1.f-vmax), radius*(1.f-vmin), umin*thetamax, umax*thetamax);
230
b.minmax[0].z = vmin*height;
231
b.minmax[1].z = vmax*height;
237
void Cone::eval(float u, float v, RtPoint P, RtVector dPdu, RtVector dPdv) const
239
const float t = u*thetamax, rv = radius*(1.f - v);
240
const float sint = sinf(t), cost = cosf(t);
241
P[0] = cost*rv, P[1] = sint*rv, P[2] = v*height;
243
const float tr = thetamax*radius*(1.f - v);
244
dPdu[0] = -sint*tr, dPdu[1] = cost*tr, dPdu[2] = 0;
245
dPdv[0] = -cost*radius, dPdv[1] = -sint*radius, dPdv[2] = height;
249
//------------------------------------------------------------------------------
252
Paraboloid::Paraboloid(): scale(1), rmax(1), zmin(0), zmax(1), thetamax(2.f*(float)M_PI)
256
Paraboloid::Paraboloid(float _rmax, float _zmin, float _zmax, float _thetamax,
257
RtInt n, RtToken tokens[], RtPointer parms[])
260
// zmin cannot be negative in this case
261
zmin = (_zmin<0.f) ? 0.f : _zmin;
262
zmax = (_zmax<0.f) ? 0.f : _zmax;
264
if (zmax!=0.f) scale /= sqrt(zmax);
265
radians(thetamax, CLAMP(ABS(_thetamax), 0.f, 360.f));
266
Primitive::initPrimVars(n, tokens, parms, 1, 4, 4, 4);
269
Bound Paraboloid::bound()
271
const float z1 = zmin + vmin*(zmax-zmin);
272
const float z2 = zmin + vmax*(zmax-zmin);
273
Bound b = bounds2DSweepL(sqrt(z1)*scale, sqrt(z2)*scale, umin*thetamax, umax*thetamax);
281
void Paraboloid::eval(float u, float v, RtPoint P, RtVector dPdu, RtVector dPdv) const
283
const float t = u*thetamax;
284
const float sint = sinf(t), cost = cosf(t);
285
const float dz = zmax - zmin;
286
const float z = zmin + v*dz;
287
const float x = sqrt(z)*scale;
288
P[0] = x*cost, P[1] = x*sint, P[2] = z;
291
const float xt = zt*scale*thetamax;
292
dPdu[0] = -xt*sint, dPdu[1] = xt*cost, dPdu[2] = 0;
293
if (zt>0.f) zt = 1.f/zt;
294
const float dx = (0.5f*dz*zt)*scale;
295
dPdv[0] = dx*cost, dPdv[1] = dx*sint, dPdv[2] = dz;
299
//------------------------------------------------------------------------------
302
Hyperboloid::Hyperboloid(): p1(-1,1,0), p2(1,-1,0), thetamax(2.f*(float)M_PI)
306
Hyperboloid::Hyperboloid(const Point3 &_point1, const Point3 &_point2, float _thetamax,
307
RtInt n, RtToken tokens[], RtPointer parms[])
308
: p1(_point1), p2(_point2)
310
radians(thetamax, CLAMP(ABS(_thetamax), 0.f, 360.f));
311
Primitive::initPrimVars(n, tokens, parms, 1, 4, 4, 4);
314
Bound Hyperboloid::bound()
316
Point3 pMin = p1 + (p2 - p1)*vmin, pMax = p1 + (p2 - p1)*vmax;
317
const float ut1 = umin*thetamax, ut2 = umax*thetamax;
318
Bound b = bounds2DSweepP(pMin, ut1, ut2);
319
b.include(bounds2DSweepP(pMax, ut1, ut2));
320
b.minmax[0].z = MIN2(pMin.z, pMax.z);
321
b.minmax[1].z = MAX2(pMin.z, pMax.z);
327
void Hyperboloid::eval(float u, float v, RtPoint P, RtVector dPdu, RtVector dPdv) const
329
const float x = p1.x + (p2.x - p1.x)*v;
330
const float y = p1.y + (p2.y - p1.y)*v;
331
const float t = u*thetamax;
332
const float sint = sinf(t), cost = cosf(t);
333
const float dx = p2.x-p1.x, dy = p2.y-p1.y, dz = p2.z-p1.z;;
334
P[0] = x*cost - y*sint, P[1] = x*sint + y*cost, P[2] = p1.z + dz*v;
336
const float xt = thetamax*(p1.x + dx*v), yt = thetamax*(p1.y + dy*v);
337
dPdu[0] = -xt*sint - yt*cost, dPdu[1] = xt*cost - yt*sint, dPdu[2] = 0;
338
dPdv[0] = dx*cost - dy*sint, dPdv[1] = dx*sint + dy*cost, dPdv[2] = dz;
342
//------------------------------------------------------------------------------
345
Torus::Torus(): majrad(1), minrad(0.25), phimin(0), phimax(2.f*(float)M_PI), thetamax(2.f*(float)M_PI)
349
Torus::Torus(float _majrad, float _minrad, float _phimin, float _phimax, float _thetamax,
350
RtInt n, RtToken tokens[], RtPointer parms[])
351
: majrad(_majrad), minrad(_minrad)
353
radians(phimin, CLAMP(ABS(_phimin), 0.f, 360.f));
354
radians(phimax, CLAMP(ABS(_phimax), 0.f, 360.f));
355
radians(thetamax, CLAMP(ABS(_thetamax), 0.f, 360.f));
356
Primitive::initPrimVars(n, tokens, parms, 1, 4, 4, 4);
361
const float myPhimin = vmin*(phimax - phimin) + phimin;
362
const float myPhimax = vmax*(phimax - phimin) + phimin;
363
Bound a = bounds2DSweepR(minrad, myPhimin, myPhimax);
364
const float rmin = a.minmax[0].x + majrad;
365
const float rmax = a.minmax[1].x + majrad;
366
Bound b = bounds2DSweepL(rmin, rmax, umin*thetamax, umax*thetamax);
367
b.minmax[0].z = a.minmax[0].y;
368
b.minmax[1].z = a.minmax[1].y;
374
void Torus::eval(float u, float v, RtPoint P, RtVector dPdu, RtVector dPdv) const
376
const float dphi = phimax - phimin;
377
const float phi = v*dphi + phimin;
378
const float sinp = sinf(phi), cosp = cosf(phi);
379
const float sx = cosp*minrad + majrad;
380
const float t = u*thetamax;
381
const float sint = sinf(t), cost = cosf(t);
382
P[0] = sx*cost, P[1] = sx*sint, P[2] = sinp*minrad;
384
const float sxt = sx*thetamax;
385
dPdu[0] = -sxt*sint, dPdu[1] = sxt*cost, dPdu[2] = 0;
386
const float dsx = -dphi*sinp*minrad;
387
dPdv[0] = dsx*cost, dPdv[1] = dsx*sint, dPdv[2] = dphi*cosp*minrad;