path_tracing.md 5.21 KB
Newer Older
yhesper's avatar
yhesper committed
1
2
---
layout: default
TheNumbat's avatar
TheNumbat committed
3
title: (Task 4) Path Tracing
yhesper's avatar
yhesper committed
4
permalink: /pathtracer/path_tracing
allai5's avatar
allai5 committed
5
parent: "A3: Pathtracer"
yhesper's avatar
yhesper committed
6
7
---

TheNumbat's avatar
TheNumbat committed
8
# (Task 4) Path Tracing
yhesper's avatar
yhesper committed
9

TheNumbat's avatar
TheNumbat committed
10
Up to this point, your renderer only computes object visibility using ray tracing. Now, we will simulate the complicated paths light can take through the scene, bouncing off many surfaces before eventually reaching the camera. Simulating this multi-bounce light is referred to as _global illumination_, and it is critical to producing realistic images, especially when specular surfaces are present.
allai5's avatar
allai5 committed
11

TheNumbat's avatar
TheNumbat committed
12
---
allai5's avatar
allai5 committed
13

TheNumbat's avatar
TheNumbat committed
14
## Step 1: `Pathtracer::trace`
allai5's avatar
allai5 committed
15

TheNumbat's avatar
TheNumbat committed
16
`Pathtracer::trace` is the function responsible for coordinating the path tracing procedure. We've given you code to intersect a ray with the scene and collect information about the surface intersection necessary for computing the lighting at that point. You should read this function and remove the early-out that colors surfaces based on their normal direction.
yhesper's avatar
yhesper committed
17

TheNumbat's avatar
TheNumbat committed
18
## Step 2: `BSDF_Lambertian`
yhesper's avatar
yhesper committed
19

Sanjay Salem's avatar
Sanjay Salem committed
20
Implement `BSDF_Lambertian::scatter`, `BSDF_Lambertian::evaluate`, and `BSDF_Lambertian::pdf`. Note that their interfaces are defined in `rays/bsdf.h`. Task 5 will further discuss sampling BSDFs, so reading ahead may help your understanding.
yhesper's avatar
yhesper committed
21

TheNumbat's avatar
TheNumbat committed
22
23
- `BSDF_Lambertian::albedo` is the ratio of incoming light to reflected light,
  also known as the base color of the Lambertian material.
Sanjay Salem's avatar
Sanjay Salem committed
24
- `BSDF_Lambertian::scatter` returns a `Scatter` object, with `direction` and `attenuation` components. You can access the material's `sampler` object to randomly sample a direction from a cosine-weighted hemisphere distribution and, you can compute the attenuation component via `BSDF_Lambertian::evaluate`.
TheNumbat's avatar
TheNumbat committed
25
26
- `BSDF_Lambertian::evaluate` computes the ratio of incoming to outgoing radiance given a pair of directions. Traditionally, BSDFs are specified as the ratio of incoming radiance to outgoing _irradiance_, which necessitates the extra `cos(theta)` factor in the rendering equation. In Scotty3D, however, we expect the BSDF to operate only on radiance, so you must scale the evaluation accordingly.
- `BSDF_Lambertian::pdf` computes the PDF for sampling some incoming direction given some outgoing direction. However, the Lambertian BSDF in particular does not depend on the outgoing direction. Since we sampled the incoming direction from a cosine-weighted hemisphere distribution, what is its PDF?
yhesper's avatar
yhesper committed
27

Sanjay Salem's avatar
Sanjay Salem committed
28
Note: a variety of sampling functions are provided in `student/samplers.cpp`. The Lambertian BSDF includes a cosine-weighted hemisphere sampler `Samplers::Hemisphere::Cosine sampler` (see `rays/bsdf.h`).
yhesper's avatar
yhesper committed
29

TheNumbat's avatar
TheNumbat committed
30
## Step 3: `Pathtracer::sample_indirect_lighting`
allai5's avatar
allai5 committed
31

TheNumbat's avatar
TheNumbat committed
32
In this function, you will estimate light that bounced off at least one other surface before reaching our shading point. This is called _indirect_ lighting.
yhesper's avatar
yhesper committed
33

TheNumbat's avatar
TheNumbat committed
34
35
36
- (1) Randomly sample a new ray direction from the BSDF distribution using BSDF::scatter().
- (2) Create a new world-space ray and call Pathtracer::trace() to get incoming light. You should modify time_bounds so that the ray does not intersect at time = 0. Remember to set the new depth value.
- (3) Compute Monte Carlo estimate of incoming _indirect_ light scaled by BSDF attenuation.
yhesper's avatar
yhesper committed
37

TheNumbat's avatar
TheNumbat committed
38
## Step 4: `Pathtracer::sample_direct_lighting`
allai5's avatar
allai5 committed
39

TheNumbat's avatar
TheNumbat committed
40
Finally, you will estimate light that hit our shading point after being emitted from a light source without any bounces in between. For now, you should use the same sampling procedure as `Pathtracer::sample_indirect_lighting`, except for using the _direct_ component of incoming light. Note that since we are only interested in light emitted from the first intersection, we can trace a ray with `depth = 0`.
allai5's avatar
allai5 committed
41

TheNumbat's avatar
TheNumbat committed
42
Note: separately sampling direct lighting might seem silly, as we could have just gotten both direct and indirect lighting from tracing a single BSDF sample. However, separating the components will allow us to improve our direct light sampling algorithm in task 6.
yhesper's avatar
yhesper committed
43
44
45

---

TheNumbat's avatar
TheNumbat committed
46
## Reference Results
yhesper's avatar
yhesper committed
47

TheNumbat's avatar
TheNumbat committed
48
After correctly implementing task 4, your renderer should be able to make a beautifully lit picture of the Cornell Box with Lambertian spheres (`cbox_lambertian.dae`). Below is a render using 1024 samples per pixel (spp):
yhesper's avatar
yhesper committed
49

TheNumbat's avatar
TheNumbat committed
50
![cbox_lambertian](images/cbox_lambertian.png)
yhesper's avatar
yhesper committed
51

TheNumbat's avatar
TheNumbat committed
52
Note the time-quality tradeoff here. This image was rendered with a sample rate of 1024 camera rays per pixel and a max ray depth of 8. This will produce a relatively high quality result, but will take quite some time to render. Rendering a fully converged image may take a even longer, so start testing your path tracer early!
yhesper's avatar
yhesper committed
53

TheNumbat's avatar
TheNumbat committed
54
Thankfully, runtime will scale (roughly) linearly with the number of samples. Below are the results and runtime of rendering the Lambertian cornell box at 720p on a Ryzen 5950x (max ray depth 8):
yhesper's avatar
yhesper committed
55

TheNumbat's avatar
TheNumbat committed
56
![cbox_lambertian_timing](images/cbox_lambertian_timing.png)
yhesper's avatar
yhesper committed
57

TheNumbat's avatar
TheNumbat committed
58
---
yhesper's avatar
yhesper committed
59

TheNumbat's avatar
TheNumbat committed
60
## Extra Credit
yhesper's avatar
yhesper committed
61

TheNumbat's avatar
TheNumbat committed
62
63
- Instead of setting a maximum ray depth, implement un-biased russian roulette for path termination. Though russian roulette will increase variance, use of a good heuristic (such as overall path throughput) should improve performance enough to show better convergence in an equal-time comparison. Refer to [Physically Based Rendering](http://www.pbr-book.org/3ed-2018/) chapter 13.7.
- (Advanced) Implement homogeneous volumetric scattering. Refer to [Physically Based Rendering](http://www.pbr-book.org/3ed-2018/) chapters 11 and 15.