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 "perspective.h"
00025 #include "sampling.h"
00026 #include "mc.h"
00027 #include "scene.h"
00028 #include "film.h"
00029 #include "reflection/bxdf.h"
00030 #include "light.h"
00031 #include "paramset.h"
00032 #include "dynload.h"
00033 #include "disk.h"
00034 #include "error.h"
00035
00036 using namespace lux;
00037
00038 #define honeyRad 0.866025403
00039 #define radIndex 57.2957795
00040
00041 class PerspectiveBxDF : public BxDF
00042 {
00043 public:
00044 PerspectiveBxDF(bool lens, float FD, float f, float A, const Point &pL,
00045 const Transform &R2C, float xS, float xE, float yS, float yE) :
00046 BxDF(BxDFType(BSDF_REFLECTION | BSDF_DIFFUSE)), hasLens(lens),
00047 FocalDistance(FD), fov(f), xStart(xS), xEnd(xE),
00048 yStart(yS), yEnd(yE), Area(A),
00049 p(pL), RasterToCamera(R2C) {}
00050 virtual ~PerspectiveBxDF() { }
00051 virtual void f(const TsPack *tspack, const Vector &wo, const Vector &wi, SWCSpectrum *const f) const
00052 {
00053 Vector wo0(wo);
00054 wo0.y = -wo0.y;
00055 if (hasLens) {
00056 wo0 *= FocalDistance / wo.z;
00057 wo0 += Vector(p.x, p.y, p.z);
00058 }
00059 const float cos = Normalize(wo0).z;
00060 const float cos2 = cos * cos;
00061 wo0 *= RasterToCamera(Point(0, 0, 0)).z / wo0.z;
00062 Point p0(RasterToCamera.GetInverse()(Point(wo0.x, wo0.y, wo0.z)));
00063 if (p0.x < xStart || p0.x >= xEnd || p0.y < yStart || p0.y >= yEnd)
00064 return;
00065 *f += SWCSpectrum(1.f / (Area * cos2 * cos2));
00066 }
00067 virtual bool Sample_f(const TsPack *tspack, const Vector &wo, Vector *wi, float u1, float u2,
00068 SWCSpectrum *const f, float *pdf, float *pdfBack = NULL, bool reverse = false) const
00069 {
00070 Point pS(RasterToCamera(Point(u1, u2, 0.f)));
00071 *wi = Vector(pS.x, pS.y, pS.z);
00072 const float cos = Normalize(*wi).z;
00073 const float cos2 = cos * cos;
00074 if (hasLens) {
00075 Point pF(Point(0, 0, 0) + *wi * (FocalDistance / wi->z));
00076 *wi = pF - p;
00077 }
00078 *wi = Normalize(*wi);
00079 wi->y = -wi->y;
00080 *pdf = 1.f / (Area * cos2 * cos);
00081 if (pdfBack)
00082 *pdfBack = *pdf;
00083 *f = SWCSpectrum(1.f / (Area * cos2 * cos2));
00084 return true;
00085 }
00086 virtual float Pdf(const TsPack *tspack, const Vector &wi, const Vector &wo) const
00087 {
00088 Vector wo0(wo);
00089 wo0.y = -wo0.y;
00090 if (hasLens) {
00091 wo0 *= FocalDistance / wo.z;
00092 wo0 += Vector(p.x, p.y, p.z);
00093 }
00094 const float cos = Normalize(wo0).z;
00095 const float cos2 = cos * cos;
00096 wo0 *= RasterToCamera(Point(0, 0, 0)).z / wo0.z;
00097 Point p0(RasterToCamera.GetInverse()(Point(wo0.x, wo0.y, wo0.z)));
00098 if (p0.x < xStart || p0.x >= xEnd || p0.y < yStart || p0.y >= yEnd)
00099 return 0.f;
00100 else
00101 return 1.f / (Area * cos2 * cos);
00102 }
00103 private:
00104 bool hasLens;
00105 float FocalDistance, fov, xStart, xEnd, yStart, yEnd, Area;
00106 Point p;
00107 const Transform &RasterToCamera;
00108 };
00109
00110
00111 PerspectiveCamera::
00112 PerspectiveCamera(const Transform &world2camStart,
00113 const Transform &world2camEnd,
00114 const float Screen[4], float hither, float yon,
00115 float sopen, float sclose, int sdist,
00116 float lensr, float focald, bool autofocus,
00117 float fov1, int dist, int sh, int pow, Film *f)
00118 : ProjectiveCamera(world2camStart, world2camEnd,
00119 Perspective(fov1, hither, yon),
00120 Screen, hither, yon, sopen, sclose, sdist,
00121 lensr, focald, f),
00122 distribution(dist), shape(sh), power(pow),
00123 autoFocus(autofocus) {
00124 pos = CameraToWorld(Point(0,0,0));
00125 normal = CameraToWorld(Normal(0,0,1));
00126 fov = Radians(fov1);
00127
00128 ParamSet paramSet;
00129 paramSet.AddFloat("radius", &LensRadius);
00130 lens = boost::shared_ptr<Shape>(Disk::CreateShape(CameraToWorld, false, paramSet));
00131
00132 if (LensRadius > 0.f)
00133 posPdf = 1.0f/(M_PI*LensRadius*LensRadius);
00134 else
00135 posPdf = 1.f;
00136
00137 R = 1.f;
00138 float templength = R * tan(fov / 2.f) * 2.f;
00139 int xS, xE, yS, yE;
00140 f->GetSampleExtent(&xS, &xE, &yS, &yE);
00141 xStart = xS;
00142 xEnd = xE;
00143 yStart = yS;
00144 yEnd = yE;
00145 xPixelWidth = templength * (Screen[1] - Screen[0]) / 2.f *
00146 (xEnd - xStart) / f->xResolution;
00147 yPixelHeight = templength * (Screen[3] - Screen[2]) / 2.f *
00148 (yEnd - yStart) / f->yResolution;
00149 Apixel = xPixelWidth * yPixelHeight;
00150 RasterToCameraBidir = Perspective(fov1, DEFAULT_EPSILON_STATIC, INFINITY).GetInverse() * RasterToScreen;
00151 WorldToRasterBidir = RasterToCameraBidir.GetInverse() * WorldToCamera;
00152 }
00153
00154 void PerspectiveCamera::AutoFocus(Scene* scene)
00155 {
00156 if (autoFocus) {
00157 std::stringstream ss;
00158
00159
00160
00161 int xstart, xend, ystart, yend;
00162 film->GetSampleExtent(&xstart, &xend, &ystart, ¥d);
00163 Point Pras((xend - xstart) / 2, (yend - ystart) / 2, 0);
00164
00165
00166
00167
00168
00169
00170 Point Pcamera;
00171 RasterToCamera(Pras, &Pcamera);
00172 Ray ray;
00173 ray.o = Pcamera;
00174 ray.d = Vector(Pcamera.x, Pcamera.y, Pcamera.z);
00175 ray.d = Normalize(ray.d);
00176
00177
00178 ray.time = 0.0f;
00179
00180 ray.mint = 0.f;
00181 ray.maxt = (ClipYon - ClipHither) / ray.d.z;
00182 CameraToWorld(ray, &ray);
00183
00184
00185
00186
00187
00188
00189 Intersection isect;
00190 if (scene->Intersect(ray, &isect))
00191 FocalDistance = ray.maxt;
00192 else
00193 luxError(LUX_NOERROR, LUX_WARNING, "Unable to define the Autofocus focal distance");
00194
00195 ss.str("");
00196 ss << "Autofocus focal distance: " << FocalDistance;
00197 luxError(LUX_NOERROR, LUX_INFO, ss.str().c_str());
00198 }
00199 }
00200
00201 float PerspectiveCamera::GenerateRay(const Sample &sample, Ray *ray) const
00202 {
00203
00204 Point Pras(sample.imageX, sample.imageY, 0);
00205 Point Pcamera;
00206 RasterToCamera(Pras, &Pcamera);
00207 ray->o = Pcamera;
00208 ray->d = Vector(Pcamera.x, Pcamera.y, Pcamera.z);
00209
00210 ray->time = GetTime(sample.time);
00211
00212 if (LensRadius > 0.)
00213 {
00214 Point lenP;
00215 Point lenPCamera;
00216
00217 SampleLens(sample.lensU, sample.lensV, &(lenPCamera.x), &(lenPCamera.y));
00218 lenPCamera.x *= LensRadius;
00219 lenPCamera.y *= LensRadius;
00220 lenPCamera.z = 0;
00221 CameraToWorld(lenPCamera, &lenP);
00222 float lensU = lenPCamera.x;
00223 float lensV = lenPCamera.y;
00224
00225
00226 float ft = (FocalDistance - ClipHither) / ray->d.z;
00227 Point Pfocus = (*ray)(ft);
00228
00229 ray->o.x += lensU * (FocalDistance - ClipHither) / FocalDistance;
00230 ray->o.y += lensV * (FocalDistance - ClipHither) / FocalDistance;
00231 ray->d = Pfocus - ray->o;
00232 }
00233 ray->d = Normalize(ray->d);
00234 ray->mint = 0.;
00235 ray->maxt = (ClipYon - ClipHither) / ray->d.z;
00236 CameraToWorld(*ray, ray);
00237 return 1.f;
00238 }
00239
00240 bool PerspectiveCamera::Sample_W(const TsPack *tspack, const Scene *scene, float u1, float u2, float u3, BSDF **bsdf, float *pdf, SWCSpectrum *We) const
00241 {
00242 Point psC(0.f);
00243 if (LensRadius > 0.f) {
00244 SampleLens(u1, u2, &psC.x, &psC.y);
00245 psC.x *= LensRadius;
00246 psC.y *= LensRadius;
00247 }
00248 Point ps = CameraToWorld(psC);
00249 DifferentialGeometry dg(ps, normal, CameraToWorld(Vector(1, 0, 0)), CameraToWorld(Vector(0, 1, 0)), Normal(0, 0, 0), Normal(0, 0, 0), 0, 0, NULL);
00250 *bsdf = BSDF_ALLOC(tspack, SingleBSDF)(dg, normal,
00251 BSDF_ALLOC(tspack, PerspectiveBxDF)(LensRadius > 0.f, FocalDistance,
00252 fov, Apixel, psC, RasterToCameraBidir,
00253 xStart, xEnd, yStart, yEnd));
00254 *pdf = posPdf;
00255 *We = SWCSpectrum(posPdf);
00256 return true;
00257 }
00258 bool PerspectiveCamera::Sample_W(const TsPack *tspack, const Scene *scene, const Point &p, const Normal &n, float u1, float u2, float u3, BSDF **bsdf, float *pdf, float *pdfDirect, VisibilityTester *visibility, SWCSpectrum *We) const
00259 {
00260 Point psC(0.f);
00261 if (LensRadius > 0.f) {
00262 SampleLens(u1, u2, &psC.x, &psC.y);
00263 psC.x *= LensRadius;
00264 psC.y *= LensRadius;
00265 }
00266 Point ps = CameraToWorld(psC);
00267 DifferentialGeometry dg(ps, normal, CameraToWorld(Vector(1, 0, 0)), CameraToWorld(Vector(0, 1, 0)), Normal(0, 0, 0), Normal(0, 0, 0), 0, 0, NULL);
00268 *bsdf = BSDF_ALLOC(tspack, SingleBSDF)(dg, normal,
00269 BSDF_ALLOC(tspack, PerspectiveBxDF)(LensRadius > 0.f, FocalDistance,
00270 fov, Apixel, psC, RasterToCameraBidir,
00271 xStart, xEnd, yStart, yEnd));
00272 *pdf = posPdf;
00273 *pdfDirect = posPdf;
00274 visibility->SetSegment(p, ps, tspack->time);
00275 *We = SWCSpectrum(posPdf);
00276 return true;
00277 }
00278
00279 BBox PerspectiveCamera::Bounds() const
00280 {
00281 BBox bound(Point(-LensRadius, -LensRadius, 0.f),
00282 Point(LensRadius, LensRadius, 0.f));
00283 bound = CameraToWorld(bound);
00284 bound.Expand(MachineEpsilon::E(bound));
00285 return bound;
00286 }
00287
00288 bool PerspectiveCamera::GetSamplePosition(const Point &p, const Vector &wi, float distance, float *x, float *y) const
00289 {
00290 Vector direction(normal);
00291 const float cosi = Dot(wi, direction);
00292 if (cosi <= 0.f || (distance != -1.f && (distance * cosi < ClipHither || distance * cosi > ClipYon)))
00293 return false;
00294 if (LensRadius > 0.f) {
00295 Point pFC(p + wi * (FocalDistance / Dot(wi, direction)));
00296 Vector wi0(pFC - pos);
00297 Point pO(pos + wi0 / Dot(wi0, direction));
00298 WorldToRasterBidir(pO, &pO);
00299 *x = pO.x;
00300 *y = pO.y;
00301 } else {
00302 Point pO = WorldToRasterBidir(pos + wi / Dot(wi, direction));
00303 *x = pO.x;
00304 *y = pO.y;
00305 }
00306 return true;
00307 }
00308
00309 void PerspectiveCamera::ClampRay(Ray &ray) const
00310 {
00311 const float cosi = Dot(ray.d, normal);
00312 ray.mint = ClipHither / cosi;
00313 ray.maxt = ClipYon / cosi;
00314 }
00315
00316 void PerspectiveCamera::SampleLens(float u1, float u2, float *dx, float *dy) const
00317 {
00318 if (shape < 3) {
00319 ConcentricSampleDisk(u1, u2, dx, dy);
00320 return;
00321 }
00322
00323 static const int subDiv = 360 / (shape * 2);
00324 static const float index = subDiv / radIndex;
00325 static const float honeyRadius = cosf(index);
00326
00327 int temp = rand() % (shape * 2);
00328
00329 float theta;
00330 if (shape == 3 && temp % 2 == 0)
00331 theta = 2.f * M_PI * (temp + sqrtf(u2)) / (shape * 2);
00332 else
00333 theta = 2.f * M_PI * (temp + u2) / (shape * 2);
00334
00335 const int sector = theta / index;
00336 const float rho = (sector % 2 == 0) ? theta - sector * index :
00337 (sector - 1) * index - theta;
00338
00339 float r = honeyRadius / cosf(rho);
00340 switch (distribution) {
00341 case 0:
00342 r *= sqrtf(u1);
00343 break;
00344 case 1:
00345 r *= sqrtf(ExponentialSampleDisk(u1, power));
00346 break;
00347 case 2:
00348 r *= sqrtf(InverseExponentialSampleDisk(u1, power));
00349 break;
00350 case 3:
00351 r *= sqrtf(GaussianSampleDisk(u1));
00352 break;
00353 case 4:
00354 r *= sqrtf(InverseGaussianSampleDisk(u1));
00355 break;
00356 case 5:
00357 r *= sqrtf(TriangularSampleDisk(u1));
00358 break;
00359 }
00360 *dx = r * cosf(theta);
00361 *dy = r * sinf(theta);
00362 }
00363
00364 Camera* PerspectiveCamera::CreateCamera(const Transform &world2camStart, const Transform &world2camEnd, const ParamSet ¶ms,
00365 Film *film)
00366 {
00367
00368 float hither = max(1e-4f, params.FindOneFloat("hither", 1e-3f));
00369 float yon = min(params.FindOneFloat("yon", 1e30f), 1e30f);
00370
00371 float shutteropen = params.FindOneFloat("shutteropen", 0.f);
00372 float shutterclose = params.FindOneFloat("shutterclose", 1.f);
00373 int shutterdist = 0;
00374 string shutterdistribution = params.FindOneString("shutterdistribution", "uniform");
00375 if (shutterdistribution == "uniform") shutterdist = 0;
00376 else if (shutterdistribution == "gaussian") shutterdist = 1;
00377 else {
00378 std::stringstream ss;
00379 ss<<"Distribution '"<<shutterdistribution<<"' for perspective camera shutter sampling unknown. Using \"uniform\".";
00380 luxError(LUX_BADTOKEN,LUX_WARNING,ss.str().c_str());
00381 shutterdist = 0;
00382 }
00383
00384 float lensradius = params.FindOneFloat("lensradius", 0.f);
00385 float focaldistance = params.FindOneFloat("focaldistance", 1e30f);
00386 bool autofocus = params.FindOneBool("autofocus", false);
00387 float frame = params.FindOneFloat("frameaspectratio",
00388 float(film->xResolution)/float(film->yResolution));
00389 float screen[4];
00390 if (frame > 1.f) {
00391 screen[0] = -frame;
00392 screen[1] = frame;
00393 screen[2] = -1.f;
00394 screen[3] = 1.f;
00395 }
00396 else {
00397 screen[0] = -1.f;
00398 screen[1] = 1.f;
00399 screen[2] = -1.f / frame;
00400 screen[3] = 1.f / frame;
00401 }
00402 int swi;
00403 const float *sw = params.FindFloat("screenwindow", &swi);
00404 if (sw && swi == 4)
00405 memcpy(screen, sw, 4*sizeof(float));
00406 float fov = params.FindOneFloat("fov", 90.);
00407
00408 int distribution = 0;
00409 string dist = params.FindOneString("distribution", "uniform");
00410 if (dist == "uniform") distribution = 0;
00411 else if (dist == "exponential") distribution = 1;
00412 else if (dist == "inverse exponential") distribution = 2;
00413 else if (dist == "gaussian") distribution = 3;
00414 else if (dist == "inverse gaussian") distribution = 4;
00415 else {
00416 std::stringstream ss;
00417 ss<<"Distribution '"<<dist<<"' for perspective camera DOF sampling unknown. Using \"uniform\".";
00418 luxError(LUX_BADTOKEN,LUX_WARNING,ss.str().c_str());
00419 distribution = 0;
00420 }
00421
00422 int shape = params.FindOneInt("blades", 0);
00423 int power = params.FindOneInt("power", 3);
00424
00425 return new PerspectiveCamera(world2camStart, world2camEnd, screen, hither, yon,
00426 shutteropen, shutterclose, shutterdist, lensradius, focaldistance, autofocus,
00427 fov, distribution, shape, power, film);
00428 }
00429
00430 static DynamicLoader::RegisterCamera<PerspectiveCamera> r("perspective");