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