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