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 "disk.h"
00025 #include "paramset.h"
00026 #include "dynload.h"
00027
00028 using namespace lux;
00029
00030
00031 Disk::Disk(const Transform &o2w, bool ro, float ht,
00032 float r, float ri, float tmax)
00033 : Shape(o2w, ro) {
00034 height = ht;
00035 radius = r;
00036 innerRadius = ri;
00037 phiMax = Radians(Clamp(tmax, 0.0f, 360.0f));
00038 }
00039 BBox Disk::ObjectBound() const {
00040 return BBox(Point(-radius, -radius, height),
00041 Point(radius, radius, height));
00042 }
00043 bool Disk::Intersect(const Ray &r, float *tHit,
00044 DifferentialGeometry *dg) const {
00045
00046 Ray ray;
00047 WorldToObject(r, &ray);
00048
00049 if (fabsf(ray.d.z) < 1e-7) return false;
00050 float thit = (height - ray.o.z) / ray.d.z;
00051 if (thit < ray.mint || thit > ray.maxt)
00052 return false;
00053
00054 Point phit = ray(thit);
00055 float dist2 = phit.x * phit.x + phit.y * phit.y;
00056 if (dist2 > radius * radius ||
00057 dist2 < innerRadius*innerRadius)
00058 return false;
00059
00060 float phi = atan2f(phit.y, phit.x);
00061 if (phi < 0) phi += 2. * M_PI;
00062 if (phi > phiMax)
00063 return false;
00064
00065 float u = phi / phiMax;
00066 float v = 1.f - ((sqrtf(dist2)-innerRadius) /
00067 (radius-innerRadius));
00068 Vector dpdu(-phiMax * phit.y, phiMax * phit.x, 0.);
00069 dpdu *= phiMax * INV_TWOPI;
00070 Vector dpdv(-phit.x / (1-v), -phit.y / (1-v), 0.);
00071 dpdv *= (radius - innerRadius) / radius;
00072 Normal dndu(0,0,0), dndv(0,0,0);
00073
00074 *dg = DifferentialGeometry(ObjectToWorld(phit),
00075 ObjectToWorld(dpdu),
00076 ObjectToWorld(dpdv),
00077 ObjectToWorld(dndu),
00078 ObjectToWorld(dndv),
00079 u, v, this);
00080
00081 *tHit = thit;
00082 return true;
00083 }
00084 bool Disk::IntersectP(const Ray &r) const {
00085
00086 Ray ray;
00087 WorldToObject(r, &ray);
00088
00089 if (fabsf(ray.d.z) < 1e-7) return false;
00090 float thit = (height - ray.o.z) / ray.d.z;
00091 if (thit < ray.mint || thit > ray.maxt)
00092 return false;
00093
00094 Point phit = ray(thit);
00095 float dist2 = phit.x * phit.x + phit.y * phit.y;
00096 if (dist2 > radius * radius ||
00097 dist2 < innerRadius*innerRadius)
00098 return false;
00099
00100 float phi = atan2f(phit.y, phit.x);
00101 if (phi < 0) phi += 2. * M_PI;
00102 if (phi > phiMax)
00103 return false;
00104 return true;
00105 }
00106 float Disk::Area() const {
00107 return phiMax * 0.5f *
00108 (radius * radius -innerRadius * innerRadius );
00109 }
00110 Shape* Disk::CreateShape(const Transform &o2w,
00111 bool reverseOrientation, const ParamSet ¶ms) {
00112 float height = params.FindOneFloat( "height", 0. );
00113 float radius = params.FindOneFloat( "radius", 1 );
00114 float inner_radius = params.FindOneFloat( "innerradius", 0 );
00115 float phimax = params.FindOneFloat( "phimax", 360 );
00116 return new Disk(o2w, reverseOrientation, height, radius, inner_radius, phimax);
00117 }
00118
00119 static DynamicLoader::RegisterShape<Disk> r("disk");