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