00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 #include "stdafx.h"
00027 #include "shapes/cone.h"
00028 #include "paramset.h"
00029 
00030 
00031 Cone::Cone(const Transform *o2w, const Transform *w2o, bool ro,
00032            float ht, float rad, float tm)
00033     : Shape(o2w, w2o, ro) {
00034     radius = rad;
00035     height = ht;
00036     phiMax = Radians( Clamp( tm, 0.0f, 360.0f ) );
00037 }
00038 
00039 
00040 BBox Cone::ObjectBound() const {
00041     Point p1 = Point( -radius, -radius, 0 );
00042     Point p2 = Point(  radius,  radius, height );
00043     return BBox( p1, p2 );
00044 }
00045 
00046 
00047 bool Cone::Intersect(const Ray &r, float *tHit, float *rayEpsilon,
00048         DifferentialGeometry *dg) const {
00049     float phi;
00050     Point phit;
00051     
00052     Ray ray;
00053     (*WorldToObject)(r, &ray);
00054 
00055     
00056     float k = radius / height;
00057     k = k*k;
00058     float A = ray.d.x * ray.d.x + ray.d.y * ray.d.y -
00059         k * ray.d.z * ray.d.z;
00060     float B = 2 * (ray.d.x * ray.o.x + ray.d.y * ray.o.y -
00061         k * ray.d.z * (ray.o.z-height) );
00062     float C = ray.o.x * ray.o.x + ray.o.y * ray.o.y -
00063         k * (ray.o.z -height) * (ray.o.z-height);
00064 
00065     
00066     float t0, t1;
00067     if (!Quadratic(A, B, C, &t0, &t1))
00068         return false;
00069 
00070     
00071     if (t0 > ray.maxt || t1 < ray.mint)
00072         return false;
00073     float thit = t0;
00074     if (t0 < ray.mint) {
00075         thit = t1;
00076         if (thit > ray.maxt) return false;
00077     }
00078 
00079     
00080     phit = ray(thit);
00081     phi = atan2f(phit.y, phit.x);
00082     if (phi < 0.) phi += 2.f*M_PI;
00083 
00084     
00085     if (phit.z < 0 || phit.z > height || phi > phiMax) {
00086         if (thit == t1) return false;
00087         thit = t1;
00088         if (t1 > ray.maxt) return false;
00089         
00090         phit = ray(thit);
00091         phi = atan2f(phit.y, phit.x);
00092         if (phi < 0.) phi += 2.f*M_PI;
00093         if (phit.z < 0 || phit.z > height || phi > phiMax)
00094             return false;
00095     }
00096 
00097     
00098     float u = phi / phiMax;
00099     float v = phit.z / height;
00100 
00101     
00102     Vector dpdu(-phiMax * phit.y, phiMax * phit.x, 0);
00103     Vector dpdv(-phit.x / (1.f - v),
00104                 -phit.y / (1.f - v), height);
00105 
00106     
00107     Vector d2Pduu = -phiMax * phiMax *
00108                     Vector(phit.x, phit.y, 0.);
00109     Vector d2Pduv = phiMax / (1.f - v) *
00110                     Vector(-phit.y, -phit.x, 0.);
00111     Vector d2Pdvv(0, 0, 0);
00112 
00113     
00114     float E = Dot(dpdu, dpdu);
00115     float F = Dot(dpdu, dpdv);
00116     float G = Dot(dpdv, dpdv);
00117     Vector N = Normalize(Cross(dpdu, dpdv));
00118     float e = Dot(N, d2Pduu);
00119     float f = Dot(N, d2Pduv);
00120     float g = Dot(N, d2Pdvv);
00121 
00122     
00123     float invEGF2 = 1.f / (E*G - F*F);
00124     Normal dndu = Normal((f*F - e*G) * invEGF2 * dpdu +
00125                          (e*F - f*E) * invEGF2 * dpdv);
00126     Normal dndv = Normal((g*F - f*G) * invEGF2 * dpdu +
00127                          (f*F - g*E) * invEGF2 * dpdv);
00128 
00129     
00130     const Transform &o2w = *ObjectToWorld;
00131     *dg = DifferentialGeometry(o2w(phit), o2w(dpdu), o2w(dpdv),
00132                                o2w(dndu), o2w(dndv), u, v, this);
00133 
00134     
00135     *tHit = thit;
00136 
00137     
00138     *rayEpsilon = 5e-4f * *tHit;
00139     return true;
00140 }
00141 
00142 
00143 
00144 bool Cone::IntersectP(const Ray &r) const {
00145     float phi;
00146     Point phit;
00147     
00148     Ray ray;
00149     (*WorldToObject)(r, &ray);
00150 
00151     
00152     float k = radius / height;
00153     k = k*k;
00154     float A = ray.d.x * ray.d.x + ray.d.y * ray.d.y -
00155         k * ray.d.z * ray.d.z;
00156     float B = 2 * (ray.d.x * ray.o.x + ray.d.y * ray.o.y -
00157         k * ray.d.z * (ray.o.z-height) );
00158     float C = ray.o.x * ray.o.x + ray.o.y * ray.o.y -
00159         k * (ray.o.z -height) * (ray.o.z-height);
00160 
00161     
00162     float t0, t1;
00163     if (!Quadratic(A, B, C, &t0, &t1))
00164         return false;
00165 
00166     
00167     if (t0 > ray.maxt || t1 < ray.mint)
00168         return false;
00169     float thit = t0;
00170     if (t0 < ray.mint) {
00171         thit = t1;
00172         if (thit > ray.maxt) return false;
00173     }
00174 
00175     
00176     phit = ray(thit);
00177     phi = atan2f(phit.y, phit.x);
00178     if (phi < 0.) phi += 2.f*M_PI;
00179 
00180     
00181     if (phit.z < 0 || phit.z > height || phi > phiMax) {
00182         if (thit == t1) return false;
00183         thit = t1;
00184         if (t1 > ray.maxt) return false;
00185         
00186         phit = ray(thit);
00187         phi = atan2f(phit.y, phit.x);
00188         if (phi < 0.) phi += 2.f*M_PI;
00189         if (phit.z < 0 || phit.z > height || phi > phiMax)
00190             return false;
00191     }
00192     return true;
00193 }
00194 
00195 
00196 float Cone::Area() const {
00197     return phiMax*height*height*
00198         sqrtf((height*height)+
00199               (radius*radius))/(2.0f*radius);
00200 }
00201 
00202 
00203 Cone *CreateConeShape(const Transform *o2w, const Transform *w2o,
00204         bool reverseOrientation, const ParamSet ¶ms) {
00205     float radius = params.FindOneFloat("radius", 1);
00206     float height = params.FindOneFloat("height", 1);
00207     float phimax = params.FindOneFloat("phimax", 360);
00208     return new Cone(o2w, w2o, reverseOrientation, height, radius, phimax);
00209 }
00210 
00211