Another useful quadric is the cylinder; pbrt provides cylinder
Shapes that are centered around the axis. The implementation is
in the files shapes/cylinder.h and
shapes/cylinder.cpp. The user
supplies a minimum and maximum value for the cylinder, as well as a
radius and maximum sweep value (Figure 3.6).
Figure 3.6: Basic Setting for the Cylinder Shape.
It has a radius of and covers a range along the
axis. A partial cylinder may be swept by specifying a maximum
value.
In parametric form, a cylinder is described by the following equations:
Figure 3.7 shows a rendered image of two
cylinders. Like the sphere image, the left cylinder is a complete
cylinder, while the right one is a partial cylinder because it has a
value less than .
Figure 3.7: Two Cylinders. A complete cylinder is
on the left, and a partial cylinder is on the right.
As was done with the sphere, the cylinder bounding method
computes a conservative bounding box using the range but without taking
into account the maximum .
The ray–cylinder intersection formula can
be found by substituting the ray equation into
the cylinder’s implicit equation, similarly to the sphere case. The implicit
equation for an infinitely long cylinder centered on the axis with radius
is
Substituting the ray equation, Equation (2.3), we have
When we expand this and find the coefficients of the quadratic equation
, we have
EFloat a = dx * dx + dy * dy;
EFloat b = 2 * (dx * ox + dy * oy);
EFloat c = ox * ox + oy * oy - EFloat(radius) * EFloat(radius);
The solution process for the quadratic equation is similar for all quadric
shapes, so some fragments from the Sphere intersection method will be
reused in the following.
Float E = Dot(dpdu, dpdu);
Float F = Dot(dpdu, dpdv);
Float G = Dot(dpdv, dpdv);
Vector3f N = Normalize(Cross(dpdu, dpdv));
Float e = Dot(N, d2Pduu);
Float f = Dot(N, d2Pduv);
Float g = Dot(N, d2Pdvv);
As with spheres, the implementation here refines the computed
intersection point to ameliorate the effect of accumulated rounding error
in the point computed by evaluating the ray equation; see
Section 3.9.4. We can then invert the parametric
description of the cylinder to compute from and ; it turns out
that the result is the same as for the sphere.
The next part of the intersection method
makes sure that the hit is in the specified range and that the angle
is acceptable. If not, it rejects the hit and checks if it has
not already been tried—this resembles the conditional logic in
Sphere::Intersect().
<<Test cylinder intersection against clipping parameters>>=
Again the value is computed by scaling to lie between 0 and 1.
Straightforward inversion of the parametric equation for the cylinder’s
value gives the parametric coordinate.
<<Find parametric representation of cylinder hit>>=
Float E = Dot(dpdu, dpdu);
Float F = Dot(dpdu, dpdv);
Float G = Dot(dpdv, dpdv);
Vector3f N = Normalize(Cross(dpdu, dpdv));
Float e = Dot(N, d2Pduu);
Float f = Dot(N, d2Pduv);
Float g = Dot(N, d2Pdvv);
Float E = Dot(dpdu, dpdu);
Float F = Dot(dpdu, dpdv);
Float G = Dot(dpdv, dpdv);
Vector3f N = Normalize(Cross(dpdu, dpdv));
Float e = Dot(N, d2Pduu);
Float f = Dot(N, d2Pduv);
Float g = Dot(N, d2Pdvv);