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 "disk.h"
00033 #include "error.h"
00034
00035 using namespace lux;
00036
00037 class PerspectiveBxDF : public BxDF
00038 {
00039 public:
00040 PerspectiveBxDF(bool lens, float FD, float f, const Point &pL, const Transform &R2C, float xW, float yH) : BxDF(BxDFType(BSDF_REFLECTION | BSDF_DIFFUSE)), hasLens(lens), FocalDistance(FD), fov(f), xWidth(xW), yHeight(yH), p(pL), RasterToCamera(R2C) {}
00041 SWCSpectrum f(const Vector &wo, const Vector &wi) const {return fabsf(wi.x / wi.z) > 1.f || fabsf(wi.y / wi.z) > 1.f ? 0.f : 1.f;}
00042 SWCSpectrum Sample_f(const Vector &wo, Vector *wi, float u1, float u2, float *pdf, float *pdfBack = NULL) const
00043 {
00044 Point pS(RasterToCamera(Point(u1 * xWidth, u2 * yHeight, 0.f)));
00045 *wi = Vector(pS.x, pS.y, pS.z);
00046 if (hasLens) {
00047 Point pF(Point(0, 0, 0) + *wi * (FocalDistance / wi->z));
00048 *wi = pF - p;
00049 }
00050 *wi = Normalize(*wi);
00051 wi->y = -wi->y;
00052 *pdf = UniformConePdf(fov * 0.5f);
00053 if (pdfBack)
00054 *pdfBack = *pdf;
00055 return 1.f;
00056 }
00057 float Pdf(const Vector &wi, const Vector &wo) const
00058 {
00059 if (hasLens) {
00060 Vector woL(wo);
00061 woL.y = -woL.y;
00062 Point pFC(p + woL * (FocalDistance / woL.z));
00063 if (fabsf(pFC.x / pFC.z) > 1.f || fabsf(pFC.y / pFC.z) > 1.f)
00064 return 0.f;
00065 else
00066 return UniformConePdf(fov * 0.5f);
00067 } else {
00068 if (fabsf(wo.x / wo.z) > 1.f || fabsf(wo.y / wo.z) > 1.f)
00069 return 0.f;
00070 else
00071 return UniformConePdf(fov * 0.5f);
00072 }
00073 }
00074 private:
00075 bool hasLens;
00076 float FocalDistance, fov, xWidth, yHeight;
00077 Point p;
00078 const Transform &RasterToCamera;
00079 };
00080
00081
00082 PerspectiveCamera::
00083 PerspectiveCamera(const Transform &world2cam,
00084 const float Screen[4], float hither, float yon,
00085 float sopen, float sclose,
00086 float lensr, float focald, bool autofocus,
00087 float fov1, Film *f)
00088 : ProjectiveCamera(world2cam,
00089 Perspective(fov1, hither, yon),
00090 Screen, hither, yon, sopen, sclose,
00091 lensr, focald, f), autoFocus(autofocus) {
00092 pos = CameraToWorld(Point(0,0,0));
00093 normal = CameraToWorld(Normal(0,0,1));
00094 fov = Radians(fov1);
00095
00096 ParamSet paramSet;
00097 paramSet.AddFloat("radius", &LensRadius);
00098 lens = boost::shared_ptr<Shape>(Disk::CreateShape(CameraToWorld, false, paramSet));
00099
00100 posPdf = 1.0f/(M_PI*LensRadius*LensRadius);
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111 R = 100;
00112 float templength=R * tan(fov*0.5f)*2;
00113 float frameaspectratio=float(f->xResolution)/float(f->yResolution);
00114 if (frameaspectratio > 1.f)
00115 {
00116 xWidth=templength*frameaspectratio;
00117 yHeight=templength;
00118 }
00119 else
00120 {
00121 xWidth=templength;
00122 yHeight=templength / frameaspectratio;
00123 }
00124 xPixelWidth = f->xResolution;
00125 yPixelHeight = f->yResolution;
00126 Apixel = xPixelWidth * yPixelHeight;
00127
00128 }
00129
00130 void PerspectiveCamera::AutoFocus(Scene* scene)
00131 {
00132 if (autoFocus) {
00133 std::stringstream ss;
00134
00135
00136
00137 int xstart, xend, ystart, yend;
00138 film->GetSampleExtent(&xstart, &xend, &ystart, ¥d);
00139 Point Pras((xend - xstart) / 2, (yend - ystart) / 2, 0);
00140
00141
00142
00143
00144
00145
00146 Point Pcamera;
00147 RasterToCamera(Pras, &Pcamera);
00148 Ray ray;
00149 ray.o = Pcamera;
00150 ray.d = Vector(Pcamera.x, Pcamera.y, Pcamera.z);
00151 ray.d = Normalize(ray.d);
00152
00153
00154 ray.time = 0.0f;
00155
00156 ray.mint = 0.f;
00157 ray.maxt = (ClipYon - ClipHither) / ray.d.z;
00158 CameraToWorld(ray, &ray);
00159
00160
00161
00162
00163
00164
00165 Intersection isect;
00166 if (scene->Intersect(ray, &isect))
00167 FocalDistance = ray.maxt;
00168 else
00169 luxError(LUX_NOERROR, LUX_WARNING, "Unable to define the Autofocus focal distance");
00170
00171 ss.str("");
00172 ss << "Autofocus focal distance: " << FocalDistance;
00173 luxError(LUX_NOERROR, LUX_INFO, ss.str().c_str());
00174 }
00175 }
00176
00177 float PerspectiveCamera::GenerateRay(const Sample &sample, Ray *ray) const
00178 {
00179
00180 Point Pras(sample.imageX, sample.imageY, 0);
00181 Point Pcamera;
00182 RasterToCamera(Pras, &Pcamera);
00183 ray->o = Pcamera;
00184 ray->d = Vector(Pcamera.x, Pcamera.y, Pcamera.z);
00185
00186 ray->time = Lerp(sample.time, ShutterOpen, ShutterClose);
00187
00188 if (LensRadius > 0.)
00189 {
00190 Point lenP;
00191 float lenPdf;
00192
00193 SamplePosition(sample.lensU, sample.lensV, &lenP, &lenPdf);
00194 Point lenPCamera(WorldToCamera(lenP));
00195 float lensU = lenPCamera.x;
00196 float lensV = lenPCamera.y;;
00197
00198
00199 float ft = (FocalDistance - ClipHither) / ray->d.z;
00200 Point Pfocus = (*ray)(ft);
00201
00202 ray->o.x += lensU * (FocalDistance - ClipHither) / FocalDistance;
00203 ray->o.y += lensV * (FocalDistance - ClipHither) / FocalDistance;
00204 ray->d = Pfocus - ray->o;
00205 }
00206 ray->d = Normalize(ray->d);
00207 ray->mint = 0.;
00208 ray->maxt = (ClipYon - ClipHither) / ray->d.z;
00209 CameraToWorld(*ray, ray);
00210 return 1.f;
00211 }
00212
00213 SWCSpectrum PerspectiveCamera::Sample_W(const Scene *scene, float u1, float u2, BSDF **bsdf, float *pdf) const
00214 {
00215 Point psC(0.f);
00216 ConcentricSampleDisk(u1, u2, &psC.x, &psC.y);
00217 psC.x *= LensRadius;
00218 psC.y *= LensRadius;
00219 Point ps = CameraToWorld(psC);
00220 Normal ns(CameraToWorld(Normal(0, 0, 1)));
00221 DifferentialGeometry dg(ps, ns, CameraToWorld(Vector(1, 0, 0)), CameraToWorld(Vector(0, 1, 0)), Vector(0, 0, 0), Vector(0, 0, 0), 0, 0, NULL);
00222 *bsdf = BSDF_ALLOC(BSDF)(dg, ns);
00223 (*bsdf)->Add(BSDF_ALLOC(PerspectiveBxDF)(LensRadius > 0.f, FocalDistance, fov, psC, RasterToCamera, xPixelWidth, yPixelHeight));
00224 *pdf = posPdf;
00225 return SWCSpectrum(1.f);
00226 }
00227 SWCSpectrum PerspectiveCamera::Sample_W(const Scene *scene, const Point &p, const Normal &n, float u1, float u2, BSDF **bsdf, float *pdf, float *pdfDirect, VisibilityTester *visibility) const
00228 {
00229 Point psC(0.f);
00230 ConcentricSampleDisk(u1, u2, &psC.x, &psC.y);
00231 psC.x *= LensRadius;
00232 psC.y *= LensRadius;
00233 Point ps = CameraToWorld(psC);
00234 Normal ns(CameraToWorld(Normal(0, 0, 1)));
00235 DifferentialGeometry dg(ps, ns, CameraToWorld(Vector(1, 0, 0)), CameraToWorld(Vector(0, 1, 0)), Vector(0, 0, 0), Vector(0, 0, 0), 0, 0, NULL);
00236 *bsdf = BSDF_ALLOC(BSDF)(dg, ns);
00237 (*bsdf)->Add(BSDF_ALLOC(PerspectiveBxDF)(LensRadius > 0.f, FocalDistance, fov, psC, RasterToCamera, xPixelWidth, yPixelHeight));
00238 *pdf = posPdf;
00239 *pdfDirect = posPdf;
00240 visibility->SetSegment(p, ps);
00241 return SWCSpectrum(1.f);
00242 }
00243 float PerspectiveCamera::Pdf(const Point &p, const Normal &n, const Vector &wi) const
00244 {
00245 return posPdf;
00246 }
00247 void PerspectiveCamera::GetSamplePosition(const Point &p, const Vector &wi, float *x, float *y) const
00248 {
00249 Point origin(0, 0, 0);
00250 CameraToWorld(origin, &origin);
00251 Vector direction(0, 0, 1);
00252 CameraToWorld(direction, &direction);
00253 if (LensRadius > 0.f) {
00254 Point pFC(p + wi * (FocalDistance / Dot(wi, direction)));
00255 Vector wi0(pFC - origin);
00256 Point pO(origin + wi0 / Dot(wi0, direction));
00257 WorldToRaster(pO, &pO);
00258 *x = pO.x;
00259 *y = pO.y;
00260 } else {
00261 Point pO = WorldToRaster(origin + wi / Dot(wi, direction));
00262 *x = pO.x;
00263 *y = pO.y;
00264 }
00265 }
00266
00267 bool PerspectiveCamera::IsVisibleFromEyes(const Scene *scene, const Point &lenP,
00268 const Point &worldP, Sample* sample_gen, Ray *ray_gen) const {
00269
00270 bool isVisible;
00271 Point point;
00272 if (LensRadius > 0)
00273 {
00274 Ray r(WorldToCamera(Ray(lenP, worldP - lenP)));
00275 float ft = FocalDistance / r.d.z;
00276 point = CameraToWorld(r(ft));
00277 }
00278 else
00279 {
00280 point = worldP;
00281 }
00282
00283 if (GenerateSample(point, sample_gen))
00284 {
00285 GenerateRay(*sample_gen, ray_gen);
00286
00287 Ray ray1(worldP, lenP-worldP, RAY_EPSILON, 1.f - RAY_EPSILON);
00288
00289
00290 {
00291 Intersection isect1;
00292 if (scene->Intersect(ray1,&isect1))
00293 {
00294 float z = WorldToCamera(isect1.dg.p).z;
00295 isVisible = z<ClipHither || z>ClipYon;
00296 }
00297 else
00298 isVisible = true;
00299 }
00300
00301
00302 }
00303 else
00304 isVisible = false;
00305 return isVisible;
00306 }
00307
00308 float PerspectiveCamera::GetConnectingFactor(const Point &lenP, const Point &worldP, const Vector &wo, const Normal &n) const
00309 {
00310 return AbsDot(wo, normal)*AbsDot(wo, n)/DistanceSquared(lenP, worldP);
00311 }
00312
00313 void PerspectiveCamera::GetFlux2RadianceFactors(Film *film, float *factors, int xPixelCount, int yPixelCount) const
00314 {
00315 float d2,cos2,cos4,detaX,detaY;
00316 int x,y;
00317 for (y = 0; y < yPixelCount; ++y)
00318 {
00319 for (x = 0; x < xPixelCount; ++x)
00320 {
00321
00322
00323
00324 detaX = 0.5f * xWidth - (x+ 0.5f) * xPixelWidth;
00325 detaY = 0.5f * yHeight - (y + 0.5f) * yPixelHeight;
00326 d2 = detaX*detaX + detaY*detaY + R*R;
00327 cos2 = R*R / d2;
00328 cos4 = cos2 * cos2;
00329 factors[x+y*xPixelCount] = R*R / (Apixel*cos4);
00330 }
00331 }
00332 }
00333
00334 void PerspectiveCamera::SamplePosition(float u1, float u2, Point *p, float *pdf) const
00335 {
00336 if (LensRadius==0.0f)
00337 {
00338 *p = pos;
00339 *pdf = 1.0f;
00340 }
00341 ConcentricSampleDisk(u1, u2, &(p->x), &(p->y));
00342 p->x *= LensRadius;
00343 p->y *= LensRadius;
00344 p->z = 0;
00345 *p = CameraToWorld(*p);
00346 *pdf = posPdf;
00347 }
00348
00349 float PerspectiveCamera::EvalPositionPdf() const
00350 {
00351 return LensRadius==0.0f ? 0 : posPdf;
00352 }
00353
00354 bool PerspectiveCamera::Intersect(const Ray &ray, Intersection *isect) const
00355 {
00356
00357 if (WorldToCamera(ray.d).z>0)
00358 return false;
00359
00360 float thit;
00361 if (!lens->Intersect(ray, &thit, &isect->dg))
00362 return false;
00363
00364 isect->primitive = NULL;
00365 isect->WorldToObject = lens->WorldToObject;
00366 ray.maxt = thit;
00367 return true;
00368 }
00369
00370 Camera* PerspectiveCamera::CreateCamera(const ParamSet ¶ms,
00371 const Transform &world2cam, Film *film) {
00372
00373 float hither = max(1e-4f, params.FindOneFloat("hither", 1e-3f));
00374 float yon = min(params.FindOneFloat("yon", 1e30f), 1e30f);
00375 float shutteropen = params.FindOneFloat("shutteropen", 0.f);
00376 float shutterclose = params.FindOneFloat("shutterclose", 1.f);
00377 float lensradius = params.FindOneFloat("lensradius", 0.f);
00378 float focaldistance = params.FindOneFloat("focaldistance", 1e30f);
00379 bool autofocus = params.FindOneBool("autofocus", false);
00380 float frame = params.FindOneFloat("frameaspectratio",
00381 float(film->xResolution)/float(film->yResolution));
00382 float screen[4];
00383 if (frame > 1.f) {
00384 screen[0] = -frame;
00385 screen[1] = frame;
00386 screen[2] = -1.f;
00387 screen[3] = 1.f;
00388 }
00389 else {
00390 screen[0] = -1.f;
00391 screen[1] = 1.f;
00392 screen[2] = -1.f / frame;
00393 screen[3] = 1.f / frame;
00394 }
00395 int swi;
00396 const float *sw = params.FindFloat("screenwindow", &swi);
00397 if (sw && swi == 4)
00398 memcpy(screen, sw, 4*sizeof(float));
00399 float fov = params.FindOneFloat("fov", 90.);
00400 return new PerspectiveCamera(world2cam, screen, hither, yon,
00401 shutteropen, shutterclose, lensradius, focaldistance, autofocus,
00402 fov, film);
00403 }