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