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
00027
00028
00029 #include "lenscomponent.h"
00030 #include "mc.h"
00031 #include "paramset.h"
00032 #include "dynload.h"
00033
00034 using namespace lux;
00035
00036
00037 LensComponent::LensComponent(const Transform &o2w, bool ro, float rad,
00038 float z0, float z1, float pm, float ap)
00039 : Shape(o2w, ro) {
00040 radius = rad;
00041 zmin = Clamp(min(z0, z1), -radius, radius);
00042 zmax = Clamp(max(z0, z1), -radius, radius);
00043 thetaMin = acosf(Clamp(zmin/radius, -1.f, 1.f));
00044 thetaMax = acosf(Clamp(zmax/radius, -1.f, 1.f));
00045 phiMax = Radians(Clamp(pm, 0.0f, 360.0f));
00046 apRadius = ap / 2.0f;
00047 }
00048 Point LensComponent::Sample(float u1, float u2, float u3, Normal *n) const {
00049 float lensU, lensV;
00050 ConcentricSampleDisk(u1, u2, &lensU, &lensV);
00051 lensU *= radius;
00052 lensV *= radius;
00053 return ObjectToWorld(Point(0,0,0)+Vector(lensU, lensV, 0.f));
00054 }
00055 BBox LensComponent::ObjectBound() const {
00056 return BBox(Point(-radius, -radius, zmin),
00057 Point(radius, radius, zmax));
00058 }
00059 bool LensComponent::Intersect(const Ray &r, float *tHit,
00060 DifferentialGeometry *dg) const {
00061 float phi;
00062 Point phit;
00063
00064 Ray ray;
00065 WorldToObject(r, &ray);
00066
00067 float A = ray.d.x*ray.d.x + ray.d.y*ray.d.y +
00068 ray.d.z*ray.d.z;
00069 float B = 2 * (ray.d.x*ray.o.x + ray.d.y*ray.o.y +
00070 ray.d.z*ray.o.z);
00071 float C = ray.o.x*ray.o.x + ray.o.y*ray.o.y +
00072 ray.o.z*ray.o.z - radius*radius;
00073
00074 float t0, t1;
00075 if (!Quadratic(A, B, C, &t0, &t1))
00076 return false;
00077
00078 if (t0 > ray.maxt || t1 < ray.mint)
00079 return false;
00080 float thit = t0;
00081 if (t0 < ray.mint) {
00082 thit = t1;
00083 if (thit > ray.maxt) return false;
00084 }
00085
00086 phit = ray(thit);
00087 phi = atan2f(phit.y, phit.x);
00088 if (phi < 0.) phi += 2.f*M_PI;
00089
00090 float dist2 = phit.x * phit.x + phit.y * phit.y;
00091 if (dist2 > apRadius * apRadius) return false;
00092
00093 float u = phi / phiMax;
00094 float theta = acosf(phit.z / radius);
00095 float v = (theta - thetaMin) / (thetaMax - thetaMin);
00096
00097 float zradius = sqrtf(phit.x*phit.x + phit.y*phit.y);
00098 float invzradius = 1.f / zradius;
00099 float cosphi = phit.x * invzradius;
00100 float sinphi = phit.y * invzradius;
00101 Vector dpdu(-phiMax * phit.y, phiMax * phit.x, 0);
00102 Vector dpdv = (thetaMax-thetaMin) *
00103 Vector(phit.z * cosphi, phit.z * sinphi,
00104 -radius * sinf(theta));
00106
00107
00108
00109
00110
00111
00112
00114
00115
00116
00117
00118
00119
00120
00122
00123
00124
00125
00126
00127
00128 *dg = DifferentialGeometry(ObjectToWorld(phit),
00129 ObjectToWorld(dpdu),
00130 ObjectToWorld(dpdv),
00131 ObjectToWorld(Normal()),
00132 ObjectToWorld(Normal()),
00133 u, v, this);
00134
00135 *tHit = thit;
00136 return true;
00137 }
00138 bool LensComponent::IntersectP(const Ray &r) const {
00139
00140 Point phit;
00141
00142 Ray ray;
00143 WorldToObject(r, &ray);
00144
00145 float A = ray.d.x*ray.d.x + ray.d.y*ray.d.y +
00146 ray.d.z*ray.d.z;
00147 float B = 2 * (ray.d.x*ray.o.x + ray.d.y*ray.o.y +
00148 ray.d.z*ray.o.z);
00149 float C = ray.o.x*ray.o.x + ray.o.y*ray.o.y +
00150 ray.o.z*ray.o.z - radius*radius;
00151
00152 float t0, t1;
00153 if (!Quadratic(A, B, C, &t0, &t1))
00154 return false;
00155
00156 if (t0 > ray.maxt || t1 < ray.mint)
00157 return false;
00158 float thit = t0;
00159 if (t0 < ray.mint) {
00160 thit = t1;
00161 if (thit > ray.maxt) return false;
00162 }
00163
00164 phit = ray(thit);
00165
00166
00167
00168 float dist2 = phit.x * phit.x + phit.y * phit.y;
00169 if (dist2 > apRadius * apRadius) return false;
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182 return true;
00183 }
00184 float LensComponent::Area() const {
00185 return phiMax * radius * (zmax-zmin);
00186 }
00187
00188 Shape* LensComponent::CreateShape(const Transform &o2w,
00189 bool reverseOrientation,
00190 const ParamSet ¶ms) {
00191 float radius = params.FindOneFloat("radius", 1.f);
00192 float zmin = params.FindOneFloat("zmin", -radius);
00193 float zmax = params.FindOneFloat("zmax", radius);
00194 float phimax = params.FindOneFloat("phimax", 360.f);
00195 float aperture = params.FindOneFloat("aperture", 1.f);
00196 return new LensComponent(o2w, reverseOrientation, radius,
00197 zmin, zmax, phimax, aperture);
00198 }
00199
00200 static DynamicLoader::RegisterShape<LensComponent> r("lenscomponent");
00201