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