00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "cylinder.h"
00025 #include "paramset.h"
00026 #include "dynload.h"
00027
00028 using namespace lux;
00029
00030
00031 Cylinder::Cylinder(const Transform &o2w, bool ro, float rad,
00032 float z0, float z1, float pm)
00033 : Shape(o2w, ro) {
00034 radius = rad;
00035 zmin = min(z0, z1);
00036 zmax = max(z0, z1);
00037 phiMax = Radians(Clamp(pm, 0.0f, 360.0f));
00038 }
00039 BBox Cylinder::ObjectBound() const {
00040 Point p1 = Point(-radius, -radius, zmin);
00041 Point p2 = Point( radius, radius, zmax);
00042 return BBox(p1, p2);
00043 }
00044 bool Cylinder::Intersect(const Ray &r, float *tHit,
00045 DifferentialGeometry *dg) const {
00046 float phi;
00047 Point phit;
00048
00049 Ray ray;
00050 WorldToObject(r, &ray);
00051
00052 float A = ray.d.x*ray.d.x + ray.d.y*ray.d.y;
00053 float B = 2 * (ray.d.x*ray.o.x + ray.d.y*ray.o.y);
00054 float C = ray.o.x*ray.o.x + ray.o.y*ray.o.y - radius*radius;
00055
00056 float t0, t1;
00057 if (!Quadratic(A, B, C, &t0, &t1))
00058 return false;
00059
00060 if (t0 > ray.maxt || t1 < ray.mint)
00061 return false;
00062 float thit = t0;
00063 if (t0 < ray.mint) {
00064 thit = t1;
00065 if (thit > ray.maxt) return false;
00066 }
00067
00068 phit = ray(thit);
00069 phi = atan2f(phit.y, phit.x);
00070 if (phi < 0.) phi += 2.f*M_PI;
00071
00072 if (phit.z < zmin || phit.z > zmax || phi > phiMax) {
00073 if (thit == t1) return false;
00074 thit = t1;
00075 if (t1 > ray.maxt) return false;
00076
00077 phit = ray(thit);
00078 phi = atan2f(phit.y, phit.x);
00079 if (phi < 0.) phi += 2.f*M_PI;
00080 if (phit.z < zmin || phit.z > zmax || phi > phiMax)
00081 return false;
00082 }
00083
00084 float u = phi / phiMax;
00085 float v = (phit.z - zmin) / (zmax - zmin);
00086
00087 Vector dpdu(-phiMax * phit.y, phiMax * phit.x, 0);
00088 Vector dpdv(0, 0, zmax - zmin);
00089
00090 Vector d2Pduu = -phiMax * phiMax *
00091 Vector(phit.x, phit.y, 0);
00092 Vector d2Pduv(0, 0, 0), d2Pdvv(0, 0, 0);
00093
00094 float E = Dot(dpdu, dpdu);
00095 float F = Dot(dpdu, dpdv);
00096 float G = Dot(dpdv, dpdv);
00097 Vector N = Normalize(Cross(dpdu, dpdv));
00098 float e = Dot(N, d2Pduu);
00099 float f = Dot(N, d2Pduv);
00100 float g = Dot(N, d2Pdvv);
00101
00102 float invEGF2 = 1.f / (E*G - F*F);
00103 Normal dndu((f*F - e*G) * invEGF2 * dpdu +
00104 (e*F - f*E) * invEGF2 * dpdv);
00105 Normal dndv((g*F - f*G) * invEGF2 * dpdu +
00106 (f*F - g*E) * invEGF2 * dpdv);
00107
00108 *dg = DifferentialGeometry(ObjectToWorld(phit),
00109 ObjectToWorld(dpdu),
00110 ObjectToWorld(dpdv),
00111 ObjectToWorld(dndu),
00112 ObjectToWorld(dndv),
00113 u, v, this);
00114
00115 *tHit = thit;
00116 return true;
00117 }
00118 bool Cylinder::IntersectP(const Ray &r) const {
00119 float phi;
00120 Point phit;
00121
00122 Ray ray;
00123 WorldToObject(r, &ray);
00124
00125 float A = ray.d.x*ray.d.x + ray.d.y*ray.d.y;
00126 float B = 2 * (ray.d.x*ray.o.x + ray.d.y*ray.o.y);
00127 float C = ray.o.x*ray.o.x + ray.o.y*ray.o.y - radius*radius;
00128
00129 float t0, t1;
00130 if (!Quadratic(A, B, C, &t0, &t1))
00131 return false;
00132
00133 if (t0 > ray.maxt || t1 < ray.mint)
00134 return false;
00135 float thit = t0;
00136 if (t0 < ray.mint) {
00137 thit = t1;
00138 if (thit > ray.maxt) return false;
00139 }
00140
00141 phit = ray(thit);
00142 phi = atan2f(phit.y, phit.x);
00143 if (phi < 0.) phi += 2.f*M_PI;
00144
00145 if (phit.z < zmin || phit.z > zmax || phi > phiMax) {
00146 if (thit == t1) return false;
00147 thit = t1;
00148 if (t1 > ray.maxt) return false;
00149
00150 phit = ray(thit);
00151 phi = atan2f(phit.y, phit.x);
00152 if (phi < 0.) phi += 2.f*M_PI;
00153 if (phit.z < zmin || phit.z > zmax || phi > phiMax)
00154 return false;
00155 }
00156 return true;
00157 }
00158 float Cylinder::Area() const {
00159 return (zmax-zmin)*phiMax*radius;
00160 }
00161 Shape* Cylinder::CreateShape(const Transform &o2w, bool reverseOrientation,
00162 const ParamSet ¶ms) {
00163 float radius = params.FindOneFloat( "radius", 1 );
00164 float zmin = params.FindOneFloat( "zmin", -1 );
00165 float zmax = params.FindOneFloat( "zmax", 1 );
00166 float phimax = params.FindOneFloat( "phimax", 360 );
00167 return new Cylinder(o2w, reverseOrientation, radius, zmin, zmax, phimax);
00168 }
00169
00170 static DynamicLoader::RegisterShape<Cylinder> r("cylinder");
00171