perspective.cpp 13.1 KB
Newer Older
Matt Pharr's avatar
Matt Pharr committed
1 2

/*
3
    pbrt source code is Copyright(c) 1998-2016
Matt Pharr's avatar
Matt Pharr committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
                        Matt Pharr, Greg Humphreys, and Wenzel Jakob.

    This file is part of pbrt.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are
    met:

    - Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

    - Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

 */


// cameras/perspective.cpp*
35
#include <filters/gaussian.h>
Matt Pharr's avatar
Matt Pharr committed
36 37 38 39 40
#include "cameras/perspective.h"
#include "paramset.h"
#include "sampler.h"
#include "sampling.h"
#include "light.h"
41
#include "stats.h"
Matt Pharr's avatar
Matt Pharr committed
42

Matt Pharr's avatar
Matt Pharr committed
43 44
namespace pbrt {

45

Matt Pharr's avatar
Matt Pharr committed
46
// PerspectiveCamera Method Definitions
47 48 49
    PerspectiveCamera::PerspectiveCamera(const AnimatedTransform &CameraToWorld, const Bounds2f &screenWindow,
                                         Float shutterOpen, Float shutterClose, Float lensRadius, Float focalDistance,
                                         Float fov, Film *film, const Medium *medium, Bokeh bokehOpt)
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
            : ProjectiveCamera(CameraToWorld, Perspective(fov, 1e-2f, 1000.f),
                               screenWindow, shutterOpen, shutterClose, lensRadius,
                               focalDistance, film, medium) {
        // Compute differential changes in origin for perspective camera rays
        dxCamera =
                (RasterToCamera(Point3f(1, 0, 0)) - RasterToCamera(Point3f(0, 0, 0)));
        dyCamera =
                (RasterToCamera(Point3f(0, 1, 0)) - RasterToCamera(Point3f(0, 0, 0)));

        // Compute image plane bounds at $z=1$ for _PerspectiveCamera_
        Point2i res = film->fullResolution;
        Point3f pMin = RasterToCamera(Point3f(0, 0, 0));
        Point3f pMax = RasterToCamera(Point3f(res.x, res.y, 0));
        pMin /= pMin.z;
        pMax /= pMax.z;
        A = std::abs((pMax.x - pMin.x) * (pMax.y - pMin.y));
        bokehOptions = std::move(bokehOpt);

    }

    Float PerspectiveCamera::GenerateRay(const CameraSample &sample,
                                         Ray *ray) const {
        ProfilePhase prof(Prof::GenerateCameraRay);
        float weight = 1.0f;
        // Compute raster and camera sample positions
        Point3f pFilm = Point3f(sample.pFilm.x, sample.pFilm.y, 0);
        Point3f pCamera = RasterToCamera(pFilm);
        *ray = Ray(Point3f(0, 0, 0), Normalize(Vector3f(pCamera)));
        // Modify ray for depth of field
79
//    std::cout << lensRadius<<std::endl;
80 81
        if (lensRadius > 0) {
            // Sample point on lens
82

83
            Point2f pLens = lensRadius * biasSample(sample, weight);
84
//        Point2f pLens = lensRadius * ConcentricSampleDisk(sample.pLens);
85
//        pLens= Point2f(1-pLens.x*pLens.x,1-pLens.y*pLens.y);
Matt Pharr's avatar
Matt Pharr committed
86

87 88 89 90 91 92 93 94 95 96 97 98
            // Compute point on plane of focus
            Float ft = focalDistance / ray->d.z;
            Point3f pFocus = (*ray)(ft);

            // Update ray for effect of lens
            ray->o = Point3f(pLens.x, pLens.y, 0);
            ray->d = Normalize(pFocus - ray->o);
        }
        ray->time = Lerp(sample.time, shutterOpen, shutterClose);
        ray->medium = medium;
        *ray = CameraToWorld(*ray);
        return weight;
Matt Pharr's avatar
Matt Pharr committed
99
    }
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115

    Float PerspectiveCamera::GenerateRayDifferential(const CameraSample &sample,
                                                     RayDifferential *ray) const {


        ProfilePhase prof(Prof::GenerateCameraRay);
        float weight = 1.0f;
        // Compute raster and camera sample positions
        Point3f pFilm = Point3f(sample.pFilm.x, sample.pFilm.y, 0);
        Point3f pCamera = RasterToCamera(pFilm);
        Vector3f dir = Normalize(Vector3f(pCamera.x, pCamera.y, pCamera.z));
        *ray = RayDifferential(Point3f(0, 0, 0), dir);
        // Modify ray for depth of field
        if (lensRadius > 0) {
            // Sample point on lens
            Point2f pLens = lensRadius * biasSample(sample, weight);
116 117 118
//        Point2f pLens = lensRadius * ConcentricSampleDisk(sample.pLens);


119 120 121
            // Compute point on plane of focus
            Float ft = focalDistance / ray->d.z;
            Point3f pFocus = (*ray)(ft);
Matt Pharr's avatar
Matt Pharr committed
122

123 124 125
            // Update ray for effect of lens
            ray->o = Point3f(pLens.x, pLens.y, 0);
            ray->d = Normalize(pFocus - ray->o);
126

127
        }
Matt Pharr's avatar
Matt Pharr committed
128

129
        float dummy;
130

131 132 133
        // Compute offset rays for _PerspectiveCamera_ ray differentials
        if (lensRadius > 0) {
            // Compute _PerspectiveCamera_ ray differentials accounting for lens
Matt Pharr's avatar
Matt Pharr committed
134

135 136
            // Sample point on lens
            Point2f pLens = lensRadius * biasSample(sample, dummy);
137
//        Point2f pLens = lensRadius * ConcentricSampleDisk(sample.pLens);
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
            Vector3f dx = Normalize(Vector3f(pCamera + dxCamera));
            Float ft = focalDistance / dx.z;
            Point3f pFocus = Point3f(0, 0, 0) + (ft * dx);
            ray->rxOrigin = Point3f(pLens.x, pLens.y, 0);
            ray->rxDirection = Normalize(pFocus - ray->rxOrigin);

            Vector3f dy = Normalize(Vector3f(pCamera + dyCamera));
            ft = focalDistance / dy.z;
            pFocus = Point3f(0, 0, 0) + (ft * dy);
            ray->ryOrigin = Point3f(pLens.x, pLens.y, 0);
            ray->ryDirection = Normalize(pFocus - ray->ryOrigin);
        } else {
            ray->rxOrigin = ray->ryOrigin = ray->o;
            ray->rxDirection = Normalize(Vector3f(pCamera) + dxCamera);
            ray->ryDirection = Normalize(Vector3f(pCamera) + dyCamera);
        }
        ray->time = Lerp(sample.time, shutterOpen, shutterClose);
        ray->medium = medium;
        *ray = CameraToWorld(*ray);
        ray->hasDifferentials = true;
        return weight;
159
    }
160

161 162 163 164 165 166
    Spectrum PerspectiveCamera::We(const Ray &ray, Point2f *pRaster2) const {
        // Interpolate camera matrix and check if $\w{}$ is forward-facing
        Transform c2w;
        CameraToWorld.Interpolate(ray.time, &c2w);
        Float cosTheta = Dot(ray.d, c2w(Vector3f(0, 0, 1)));
        if (cosTheta <= 0) return 0;
167

168 169 170
        // Map ray $(\p{}, \w{})$ onto the raster grid
        Point3f pFocus = ray((lensRadius > 0 ? focalDistance : 1) / cosTheta);
        Point3f pRaster = Inverse(RasterToCamera)(Inverse(c2w)(pFocus));
171

172 173
        // Return raster position if requested
        if (pRaster2) *pRaster2 = Point2f(pRaster.x, pRaster.y);
174

175 176 177 178 179
        // Return zero importance for out of bounds points
        Bounds2i sampleBounds = film->GetSampleBounds();
        if (pRaster.x < sampleBounds.pMin.x || pRaster.x >= sampleBounds.pMax.x ||
            pRaster.y < sampleBounds.pMin.y || pRaster.y >= sampleBounds.pMax.y)
            return 0;
180

181 182
        // Compute lens area of perspective camera
        Float lensArea = lensRadius != 0 ? (Pi * lensRadius * lensRadius) : 1;
183

184 185 186 187
        // Return importance for point on image plane
        Float cos2Theta = cosTheta * cosTheta;
        return Spectrum(1 / (A * lensArea * cos2Theta * cos2Theta));
    }
188

189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
    void PerspectiveCamera::Pdf_We(const Ray &ray, Float *pdfPos,
                                   Float *pdfDir) const {
        // Interpolate camera matrix and fail if $\w{}$ is not forward-facing
        Transform c2w;
        CameraToWorld.Interpolate(ray.time, &c2w);
        Float cosTheta = Dot(ray.d, c2w(Vector3f(0, 0, 1)));
        if (cosTheta <= 0) {
            *pdfPos = *pdfDir = 0;
            return;
        }

        // Map ray $(\p{}, \w{})$ onto the raster grid
        Point3f pFocus = ray((lensRadius > 0 ? focalDistance : 1) / cosTheta);
        Point3f pRaster = Inverse(RasterToCamera)(Inverse(c2w)(pFocus));

        // Return zero probability for out of bounds points
        Bounds2i sampleBounds = film->GetSampleBounds();
        if (pRaster.x < sampleBounds.pMin.x || pRaster.x >= sampleBounds.pMax.x ||
            pRaster.y < sampleBounds.pMin.y || pRaster.y >= sampleBounds.pMax.y) {
            *pdfPos = *pdfDir = 0;
            return;
        }

        // Compute lens area of perspective camera
        Float lensArea = lensRadius != 0 ? (Pi * lensRadius * lensRadius) : 1;
        *pdfPos = 1 / lensArea;
        *pdfDir = 1 / (A * cosTheta * cosTheta * cosTheta);
    }
217

218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
    Spectrum PerspectiveCamera::Sample_Wi(const Interaction &ref, const Point2f &u,
                                          Vector3f *wi, Float *pdf,
                                          Point2f *pRaster,
                                          VisibilityTester *vis) const {
        // Uniformly sample a lens interaction _lensIntr_
        Point2f pLens = lensRadius * ConcentricSampleDisk(u);
        Point3f pLensWorld = CameraToWorld(ref.time, Point3f(pLens.x, pLens.y, 0));
        Interaction lensIntr(pLensWorld, ref.time, medium);
        lensIntr.n = Normal3f(CameraToWorld(ref.time, Vector3f(0, 0, 1)));

        // Populate arguments and compute the importance value
        *vis = VisibilityTester(ref, lensIntr);
        *wi = lensIntr.p - ref.p;
        Float dist = wi->Length();
        *wi /= dist;

        // Compute PDF for importance arriving at _ref_

        // Compute lens area of perspective camera
        Float lensArea = lensRadius != 0 ? (Pi * lensRadius * lensRadius) : 1;
        *pdf = (dist * dist) / (AbsDot(lensIntr.n, *wi) * lensArea);
        return We(lensIntr.SpawnRay(-*wi), pRaster);
    }
241

242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
    PerspectiveCamera *CreatePerspectiveCamera(const ParamSet &params,
                                               const AnimatedTransform &cam2world,
                                               Film *film, const Medium *medium) {
        // Extract common camera parameters from _ParamSet_
        Float shutteropen = params.FindOneFloat("shutteropen", 0.f);
        Float shutterclose = params.FindOneFloat("shutterclose", 1.f);
        if (shutterclose < shutteropen) {
            Warning("Shutter close time [%f] < shutter open [%f].  Swapping them.",
                    shutterclose, shutteropen);
            std::swap(shutterclose, shutteropen);
        }
        Float lensradius = params.FindOneFloat("lensradius", 0.f);
        Float focaldistance = params.FindOneFloat("focaldistance", 1e6);
        Float frame = params.FindOneFloat(
                "frameaspectratio",
                Float(film->fullResolution.x) / Float(film->fullResolution.y));
        Bounds2f screen;
        if (frame > 1.f) {
            screen.pMin.x = -frame;
            screen.pMax.x = frame;
            screen.pMin.y = -1.f;
            screen.pMax.y = 1.f;
        } else {
            screen.pMin.x = -1.f;
            screen.pMax.x = 1.f;
            screen.pMin.y = -1.f / frame;
            screen.pMax.y = 1.f / frame;
        }
        int swi;
        const Float *sw = params.FindFloat("screenwindow", &swi);
        if (sw) {
            if (swi == 4) {
                screen.pMin.x = sw[0];
                screen.pMax.x = sw[1];
                screen.pMin.y = sw[2];
                screen.pMax.y = sw[3];
            } else
                Error("\"screenwindow\" should have four values");
        }


        Float fov = params.FindOneFloat("fov", 90.);
        Float halffov = params.FindOneFloat("halffov", -1.f);

        Bokeh bokehOptions;

        int edges = params.FindOneInt("lenselements", 0);
        bokehOptions.blades = edges;
        initBokehVerts(bokehOptions);


        bokehOptions.innerRadius = params.FindOneFloat("innerRadius", 1.0);
        bokehOptions.rateOfChange = params.FindOneFloat("rateOfChange", 0.0f);

296 297
        bokehOptions.weightDistr = params.FindOneFloat("weightDistr", 2.0);

298 299 300 301
        bokehOptions.weightStrength = params.FindOneFloat("weightStrength", 0.0);
        if (bokehOptions.weightStrength < 0 || bokehOptions.weightStrength > 1) {
            Error("For \"weightStrength\" values above 1 or below 0 light conversation is violated");
        }
302 303
        bokehOptions.weightStrength = bokehOptions.weightStrength * (bokehOptions.weightDistr+1);
        bokehOptions.integral = bokehOptions.weightStrength / (bokehOptions.weightDistr+1) ;
304 305 306 307 308 309 310 311


        if (halffov > 0.f)
            // hack for structure synth, which exports half of the full fov
            fov = 2.f * halffov;
        return new PerspectiveCamera(cam2world, screen, shutteropen, shutterclose, lensradius, focaldistance, fov, film,
                                     medium, std::move(bokehOptions));
    }
Matt Pharr's avatar
Matt Pharr committed
312 313

}  // namespace pbrt