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