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