void RealisticCamera::DrawRayPathFromScene(const Ray &r, bool arrow, bool toOpticalIntercept) const { Float elementZ = LensFrontZ() * -1; // Transform _ray_ from camera to lens system space static const Transform CameraToLens = Scale(1, 1, -1); Ray ray = CameraToLens(r); for (size_t i = 0; i < elementInterfaces.size(); ++i) { const LensElementInterface &element = elementInterfaces[i]; bool isStop = (element.curvatureRadius == 0); // Compute intersection of ray with lens element Float t; Normal3f n; if (isStop) t = -(ray.o.z - elementZ) / ray.d.z; else { Float radius = element.curvatureRadius; Float zCenter = elementZ + element.curvatureRadius; if (!IntersectSphericalElement(radius, zCenter, ray, &t, &n)) return; } Assert(t >= 0.f); printf("Line[{{%f, %f}, {%f, %f}}],", ray.o.z, ray.o.x, ray(t).z, ray(t).x); // Test intersection point against element aperture Point3f pHit = ray(t); Float r2 = pHit.x * pHit.x + pHit.y * pHit.y; Float apertureRadius2 = element.apertureRadius * element.apertureRadius; if (r2 > apertureRadius2) return; ray.o = pHit; // Update ray path for from-scene element interface interaction if (!isStop) { Vector3f wt; Float etaI = (i == 0 || elementInterfaces[i - 1].eta == 0.f) ? 1.f : elementInterfaces[i - 1].eta; Float etaT = (elementInterfaces[i].eta != 0.f) ? elementInterfaces[i].eta : 1.f; if (!Refract(Normalize(-ray.d), n, etaI / etaT, &wt)) return; ray.d = wt; } elementZ += element.thickness; } // go to the film plane by default { Float ta = -ray.o.z / ray.d.z; if (toOpticalIntercept) { ta = -ray.o.x / ray.d.x; printf("Point[{%f, %f}], ", ray(ta).z, ray(ta).x); } printf("%s[{{%f, %f}, {%f, %f}}]", arrow ? "Arrow" : "Line", ray.o.z, ray.o.x, ray(ta).z, ray(ta).x); } }
bool RealisticCamera::TraceLensesFromScene(const Ray &rCamera, Ray *rOut) const { Float elementZ = -LensFrontZ(); // Transform _rCamera_ from camera to lens system space static const Transform CameraToLens = Scale(1, 1, -1); Ray rLens = CameraToLens(rCamera); for (size_t i = 0; i < elementInterfaces.size(); ++i) { const LensElementInterface &element = elementInterfaces[i]; // Compute intersection of ray with lens element Float t; Normal3f n; bool isStop = (element.curvatureRadius == 0); if (isStop) t = (elementZ - rLens.o.z) / rLens.d.z; else { Float radius = element.curvatureRadius; Float zCenter = elementZ + element.curvatureRadius; if (!IntersectSphericalElement(radius, zCenter, rLens, &t, &n)) return false; } Assert(t >= 0); // Test intersection point against element aperture Point3f pHit = rLens(t); Float r2 = pHit.x * pHit.x + pHit.y * pHit.y; if (r2 > element.apertureRadius * element.apertureRadius) return false; rLens.o = pHit; // Update ray path for from-scene element interface interaction if (!isStop) { Vector3f wt; Float etaI = (i == 0 || elementInterfaces[i - 1].eta == 0) ? 1 : elementInterfaces[i - 1].eta; Float etaT = (elementInterfaces[i].eta != 0) ? elementInterfaces[i].eta : 1; if (!Refract(Normalize(-rLens.d), n, etaI / etaT, &wt)) return false; rLens.d = wt; } elementZ += element.thickness; } // Transform _rLens_ from lens system space back to camera space if (rOut != nullptr) { static const Transform LensToCamera = Scale(1, 1, -1); *rOut = LensToCamera(rLens); } return true; }
void RealisticCamera::ComputeThickLensApproximation(Float pz[2], Float fz[2]) const { // Find height $x$ from optical axis for parallel rays Float x = .001 * film->diagonal; // Compute cardinal points for film side of lens system Ray rScene(Point3f(x, 0, LensFrontZ() + 1), Vector3f(0, 0, -1)); Ray rFilm; bool ok = TraceLensesFromScene(rScene, &rFilm); if (!ok) Severe( "Unable to trace ray from scene to film for thick lens " "approximation. Is aperture stop extremely small?"); ComputeCardinalPoints(rScene, rFilm, &pz[0], &fz[0]); // Compute cardinal points for scene side of lens system rFilm = Ray(Point3f(x, 0, LensRearZ() - 1), Vector3f(0, 0, 1)); ok = TraceLensesFromFilm(rFilm, &rScene); if (!ok) Severe( "Unable to trace ray from film to scene for thick lens " "approximation. Is aperture stop extremely small?"); ComputeCardinalPoints(rFilm, rScene, &pz[1], &fz[1]); }
void RealisticCamera::DrawLensSystem() const { Float sumz = -LensFrontZ(); Float z = sumz; for (size_t i = 0; i < elementInterfaces.size(); ++i) { const LensElementInterface &element = elementInterfaces[i]; Float r = element.curvatureRadius; if (r == 0) { // stop printf("{Thick, Line[{{%f, %f}, {%f, %f}}], ", z, element.apertureRadius, z, 2 * element.apertureRadius); printf("Line[{{%f, %f}, {%f, %f}}]}, ", z, -element.apertureRadius, z, -2 * element.apertureRadius); } else { Float theta = std::abs(std::asin(element.apertureRadius / r)); if (r > 0) { // convex as seen from front of lens Float t0 = Pi - theta; Float t1 = Pi + theta; printf("Circle[{%f, 0}, %f, {%f, %f}], ", z + r, r, t0, t1); } else { // concave as seen from front of lens Float t0 = -theta; Float t1 = theta; printf("Circle[{%f, 0}, %f, {%f, %f}], ", z + r, -r, t0, t1); } if (element.eta != 0 && element.eta != 1) { // connect top/bottom to next element Assert(i + 1 < elementInterfaces.size()); Float nextApertureRadius = elementInterfaces[i + 1].apertureRadius; Float h = std::max(element.apertureRadius, nextApertureRadius); Float hlow = std::min(element.apertureRadius, nextApertureRadius); Float zp0, zp1; if (r > 0) { zp0 = z + element.curvatureRadius - element.apertureRadius / std::tan(theta); } else { zp0 = z + element.curvatureRadius + element.apertureRadius / std::tan(theta); } Float nextCurvatureRadius = elementInterfaces[i + 1].curvatureRadius; Float nextTheta = std::abs( std::asin(nextApertureRadius / nextCurvatureRadius)); if (nextCurvatureRadius > 0) { zp1 = z + element.thickness + nextCurvatureRadius - nextApertureRadius / std::tan(nextTheta); } else { zp1 = z + element.thickness + nextCurvatureRadius + nextApertureRadius / std::tan(nextTheta); } // Connect tops printf("Line[{{%f, %f}, {%f, %f}}], ", zp0, h, zp1, h); printf("Line[{{%f, %f}, {%f, %f}}], ", zp0, -h, zp1, -h); // vertical lines when needed to close up the element profile if (element.apertureRadius < nextApertureRadius) { printf("Line[{{%f, %f}, {%f, %f}}], ", zp0, h, zp0, hlow); printf("Line[{{%f, %f}, {%f, %f}}], ", zp0, -h, zp0, -hlow); } else if (element.apertureRadius > nextApertureRadius) { printf("Line[{{%f, %f}, {%f, %f}}], ", zp1, h, zp1, hlow); printf("Line[{{%f, %f}, {%f, %f}}], ", zp1, -h, zp1, -hlow); } } } z += element.thickness; } // 24mm height for 35mm film printf("Line[{{0, -.012}, {0, .012}}], "); // optical axis printf("Line[{{0, 0}, {%f, 0}}] ", 1.2f * sumz); }