Skip to content

(Task 1) Generating Camera Rays

Joy Alice Gu edited this page Apr 16, 2020 · 15 revisions

"Camera rays" emanate from the camera and measure the amount of scene radiance that reaches a point on the camera's sensor plane. (Given a point on the virtual sensor plane, there is a corresponding camera ray that is traced into the scene.)

Take a look at Pathtracer::raytrace_pixel() in pathtracer.cpp. The job of this function is to compute the amount of energy arriving at this pixel of the image. Conveniently, we've given you a function Pathtracer::trace_ray(r) that provides a measurement of incoming scene radiance along the direction given by ray r.

When the number of samples per pixel is 1, you should sample incoming radiance at the center of each pixel by constructing a ray r that begins at this sensor location and travels through the camera's pinhole. Once you have computed this ray, then call Pathtracer::trace_ray(r) to get the energy deposited in the pixel.

Here are some rough notes giving more detail on how to generate camera rays.

This tutorial from Scratchapixel also provides a detailed walthrough of what you need to do.

Step 1: Given the width and height of the screen, and point in screen space, compute the corresponding coordinates of the point in normalized ([0-1]x[0-1]) screen space in Pathtracer::raytrace_pixel(). Pass these coordinates to the camera via Camera::generate_ray() in camera.cpp.

Step 2: Implement Camera::generate_ray(). This function should return a ray in world space that reaches the given sensor sample point. We recommend that you compute this ray in camera space (where the camera pinhole is at the origin, the camera is looking down the -Z axis, and +Y is at the top of the screen.) Note that the camera maintains camera-space-to-world space transform c2w that will be handy. The Camera class stores vFov and hFov parameters (in degrees, not radians), indicating the vertical and horizontal field of view of the camera.

Step 3: Your implementation of Pathtracer::raytrace_pixel() must support supersampling (more than one sample per pixel). The member Pathtracer::ns_aa in the raytracer class gives the number of samples of scene radiance your ray tracer should take per pixel (a.k.a. the number of camera rays per pixel. You should implement UniformGridSampler2D::gridSampler->get_sample() (see sampler.cpp), such that it provides uniformly distributed random 2D points in the [0-1]^2 box. Supersampling should be implemented by calling get_sample() to obtain randomly chosen points within the pixel.

Once you have implemented Pathtracer::raytrace_pixel(), UniformGridSampler2D::get_sample() and Camera::generate_ray(), you should have a working camera.

Tips:

  • Since it'll be hard to know if you camera rays are correct until you implement primitive intersection, we recommend debugging your camera rays by checking what your implementation of Camera::generate_ray() does with rays at the center of the screen (0.5, 0.5) and at the corners of the image.
  • The code can log the results of raytracing for visualization and debugging. To do so, uncomment the #define ENABLE_RAY_LOGGING 1 near the top of pathtracer.cpp. After running the ray tracer, rays will be shown as lines in visualizer. Press v to switch to the visualizer, and use s to toggle showing rays. A yellow ray indicates that it intersected some primitive (which you will implement soon). Be sure to wait for rendering to complete so you see all rays while visualizing, a message is printed to standard output on completion. Ray logging is NOT thread-safe, so only use with a single thread (the default -t 1 setting) and remember to comment it out when you render using multiple threads.

Extra credit ideas:

  • Modify the implementation of the camera to simulate a camera with a finite aperture (rather than a pinhole camera). This will allow your ray tracer to simulate the effect of defocus blur.
  • Write your own Sampler2D implementation that generates samples with improved distribution. Some examples include:
    • Jittered Sampling
    • Multi-jittered sampling
    • N-Rooks (Latin Hypercube) sampling
    • Sobol sequence sampling
    • Halton sequence sampling
    • Hammersley sequence sampling
Clone this wiki locally