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