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 Disk : public Shape {
00028 public:
00029
00030 Disk(const Transform &o2w, bool ro, float height,
00031 float radius, float innerRadius, float phiMax);
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 Point Sample(float u1, float u2, Normal *Ns) const {
00038 Point p;
00039 ConcentricSampleDisk(u1, u2, &p.x, &p.y);
00040 p.x *= radius;
00041 p.y *= radius;
00042 p.z = height;
00043 *Ns = Normalize(ObjectToWorld(Normal(0,0,1)));
00044 if (reverseOrientation) *Ns *= -1.f;
00045 return ObjectToWorld(p);
00046 }
00047 private:
00048
00049 float height, radius, innerRadius, phiMax;
00050 };
00051
00052 Disk::Disk(const Transform &o2w, bool ro, float ht,
00053 float r, float ri, float tmax)
00054 : Shape(o2w, ro) {
00055 height = ht;
00056 radius = r;
00057 innerRadius = ri;
00058 phiMax = Radians(Clamp(tmax, 0.0f, 360.0f));
00059 }
00060 BBox Disk::ObjectBound() const {
00061 return BBox(Point(-radius, -radius, height),
00062 Point(radius, radius, height));
00063 }
00064 bool Disk::Intersect(const Ray &r, float *tHit,
00065 DifferentialGeometry *dg) const {
00066
00067 Ray ray;
00068 WorldToObject(r, &ray);
00069
00070 if (fabsf(ray.d.z) < 1e-7) return false;
00071 float thit = (height - ray.o.z) / ray.d.z;
00072 if (thit < ray.mint || thit > ray.maxt)
00073 return false;
00074
00075 Point phit = ray(thit);
00076 float dist2 = phit.x * phit.x + phit.y * phit.y;
00077 if (dist2 > radius * radius ||
00078 dist2 < innerRadius*innerRadius)
00079 return false;
00080
00081 float phi = atan2f(phit.y, phit.x);
00082 if (phi < 0) phi += 2. * M_PI;
00083 if (phi > phiMax)
00084 return false;
00085
00086 float u = phi / phiMax;
00087 float v = 1.f - ((sqrtf(dist2)-innerRadius) /
00088 (radius-innerRadius));
00089 Vector dpdu(-phiMax * phit.y, phiMax * phit.x, 0.);
00090 dpdu *= phiMax * INV_TWOPI;
00091 Vector dpdv(-phit.x / (1-v), -phit.y / (1-v), 0.);
00092 dpdv *= (radius - innerRadius) / radius;
00093 Vector dndu(0,0,0), dndv(0,0,0);
00094
00095 *dg = DifferentialGeometry(ObjectToWorld(phit),
00096 ObjectToWorld(dpdu),
00097 ObjectToWorld(dpdv),
00098 ObjectToWorld(dndu),
00099 ObjectToWorld(dndv),
00100 u, v, this);
00101
00102 *tHit = thit;
00103 return true;
00104 }
00105 bool Disk::IntersectP(const Ray &r) const {
00106
00107 Ray ray;
00108 WorldToObject(r, &ray);
00109
00110 if (fabsf(ray.d.z) < 1e-7) return false;
00111 float thit = (height - ray.o.z) / ray.d.z;
00112 if (thit < ray.mint || thit > ray.maxt)
00113 return false;
00114
00115 Point phit = ray(thit);
00116 float dist2 = phit.x * phit.x + phit.y * phit.y;
00117 if (dist2 > radius * radius ||
00118 dist2 < innerRadius*innerRadius)
00119 return false;
00120
00121 float phi = atan2f(phit.y, phit.x);
00122 if (phi < 0) phi += 2. * M_PI;
00123 if (phi > phiMax)
00124 return false;
00125 return true;
00126 }
00127 float Disk::Area() const {
00128 return phiMax * 0.5f *
00129 (radius * radius -innerRadius * innerRadius );
00130 }
00131 extern "C" DLLEXPORT Shape *CreateShape(const Transform &o2w,
00132 bool reverseOrientation, const ParamSet ¶ms) {
00133 float height = params.FindOneFloat( "height", 0. );
00134 float radius = params.FindOneFloat( "radius", 1 );
00135 float inner_radius = params.FindOneFloat( "innerradius", 0 );
00136 float phimax = params.FindOneFloat( "phimax", 360 );
00137 return new Disk(o2w, reverseOrientation, height, radius, inner_radius, phimax);
00138 }