-
Notifications
You must be signed in to change notification settings - Fork 65
(Task 1) Generating Camera Rays
"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.
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.
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 ofpathtracer.cpp
. After running the ray tracer, rays will be shown as lines in visualizer. Pressv
to switch to the visualizer, and uses
to toggle showing rays. A yellow ray indicates that it intersected some primitive (which you will implement soon).
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
- Task 1: Camera Rays
- Task 2: Intersecting Primitives
- Task 3: BVH
- Task 4: Shadow Rays
- Task 5: Path Tracing
- Task 6: Materials
- Task 7: Environment Light
Notes:
- Task 1: Spline Interpolation
- Task 2: Skeleton Kinematics
- Task 3: Linear Blend Skinning
- Task 4: Physical Simulation
Notes: