environment_lighting.md 7.43 KB
Newer Older
Hui Wang's avatar
Hui Wang committed
1
2
[[Home]](/docs/index.md)  [[User Guide]](/docs/guide/guide.md) [[Mesh Edit]](/docs/meshedit/overview.md) [[Path Tracer]](/docs/pathtracer/overview.md) [[Animation]](/docs/animation/overview.md)

yhesper's avatar
yhesper committed
3
4
5
6
---

# (Task 7) Environment Lighting

TheNumbat's avatar
TheNumbat committed
7
## Walkthrough
Hui Wang's avatar
Hui Wang committed
8
9
<video width="750" height="500" controls><source src="videos/Task7_EnvMap.mp4" type="video/mp4"></video>
![](./videos/Task7_EnvMap.mp4)
allai5's avatar
allai5 committed
10

Hui Wang's avatar
Hui Wang committed
11
12
13
14
**Note**: The phi/theta direction in the video may be confusing, so please refer to the axis direction in the following figure. We will fix the video soon.

![envmap_angle_figure](./figures/envmap_angle_figure.png)

yhesper's avatar
yhesper committed
15
16
17
18
The final task of this assignment will be to implement a new type of light source: an infinite environment light. An environment light is a light that supplies incident radiance (really, the light intensity dPhi/dOmega) from all directions on the sphere. Rather than using a predefined collection of explicit lights, an environment light is a capture of the actual incoming light from some real-world scene; rendering using environment lighting can be quite striking.

The intensity of incoming light from each direction is defined by a texture map parameterized by phi and theta, as shown below.

Hui Wang's avatar
Hui Wang committed
19
![envmap_figure](./figures/envmap_figure.jpg)
yhesper's avatar
yhesper committed
20

TheNumbat's avatar
TheNumbat committed
21
In this task you will implement `Env_Map::sample`, `Env_Map::pdf`, and `Env_Map::evaluate` in `student/env_light.cpp`. You'll start with uniform sampling to get things working, and then move onto a more advanced implementation that uses **importance sampling** to significantly reduce variance in rendered images.
yhesper's avatar
yhesper committed
22

TheNumbat's avatar
TheNumbat committed
23
---
yhesper's avatar
yhesper committed
24

TheNumbat's avatar
TheNumbat committed
25
## Step 1: Uniformly sampling the environment map
yhesper's avatar
yhesper committed
26

TheNumbat's avatar
TheNumbat committed
27
To get things working, your first implementation of `Env_Map::sample` will be quite simple. First, check out the interface of `Env_Map` in `rays/env_light.h`. For `Env_Map`, the `image` field is a `HDR_Image`, which contains the size and pixels of the environment map. The `HDR_Image` interface may be found in `util/hdr_image.h`.
yhesper's avatar
yhesper committed
28

TheNumbat's avatar
TheNumbat committed
29
Second, implement the uniform sphere sampler in `student/samplers.cpp`. Implement `Env_Map::sample` using `uniform_sampler` to generate a direction uniformly at random. Implement `Env_Map::pdf` by returning the PDF of a uniform sphere distribution.
yhesper's avatar
yhesper committed
30

TheNumbat's avatar
TheNumbat committed
31
Lastly, in `Env_Map::evaluate`, convert the given direction to image coordinates (phi and theta) and look up the appropriate radiance value in the texture map using **bilinear interpolation**.
Hesper Yin's avatar
Hesper Yin committed
32

Hui Wang's avatar
Hui Wang committed
33
Since high dynamic range environment maps can be large files, we have not included them in the Scotty3D repository. For more HDRIs for creative environment maps, check out [Poly Haven](https://polyhaven.com/hdris/)
yhesper's avatar
yhesper committed
34

TheNumbat's avatar
TheNumbat committed
35
To use a particular environment map with your scene, select `layout` -> `new light` -> `environment map`-> `add`, and  select your file. For more creative environment maps, check out [Poly Haven](https://polyhaven.com/)
yhesper's avatar
yhesper committed
36

Hui Wang's avatar
Hui Wang committed
37
![envmap_gui](./images/envmap_gui.png)
yhesper's avatar
yhesper committed
38
39
40
41


## Step 2: Importance sampling the environment map

TheNumbat's avatar
TheNumbat committed
42
Much like light in the real world, most of the energy provided by an environment light source is concentrated in the directions toward bright light sources. Therefore, it makes sense to prefer sampling directions for which incoming radiance is the greatest. For environment lights with large variation in incoming light intensities, good importance sampling will significantly reduce the variance of your renderer.
yhesper's avatar
yhesper committed
43

TheNumbat's avatar
TheNumbat committed
44
The basic idea of importance sampling an image is assigning a probability to each pixel based on the total radiance coming from the solid angle it subtends.
Hesper Yin's avatar
Hesper Yin committed
45

TheNumbat's avatar
TheNumbat committed
46
A pixel with coordinate <img src="figures/environment_eq1.png" width ="45"> subtends an area <img src="figures/environment_eq2.png" width = "80"> on the unit sphere (where <img src="figures/environment_eq3.png" width = "20"> and <img src="figures/environment_eq4.png" width = "20"> are the angles subtended by each pixel as determined by the resolution of the texture). Thus, the flux through a pixel is proportional to <img src="figures/environment_eq5.png" width = "45">. (Since we are creating a distribution, we only care about the relative flux through each pixel, not the absolute flux.)
Hesper Yin's avatar
Hesper Yin committed
47

TheNumbat's avatar
TheNumbat committed
48
**Summing the flux for all pixels, then normalizing each such that they sum to one, yields a discrete probability distribution over the pixels where the probability one is chosen is proportional to its flux.**
Hesper Yin's avatar
Hesper Yin committed
49

TheNumbat's avatar
TheNumbat committed
50
The question is now how to efficiently get samples from this discrete distribution. To do so, we recommend treating the distribution as a single vector representing the whole image (row-major). In this form, it is easy to compute its CDF: the CDF for each pixel is the sum of the PDFs of all pixels before it. Once you have a CDF, you can use inversion sampling to pick out a particular index and convert it to a pixel and a 3D direction.
yhesper's avatar
yhesper committed
51

TheNumbat's avatar
TheNumbat committed
52
The bulk of the importance sampling algorithm will be found as `Samplers::Sphere::Image` in `student\samplers.cpp`. You will need to implement the constructor, the inversion sampling function, and the PDF function, which returns the value of your PDF at a particular direction. Once these methods are complete, upgrade `Env_Map::sample` and `Env_Map::pdf` to use your new `image_sampler`.
yhesper's avatar
yhesper committed
53

TheNumbat's avatar
TheNumbat committed
54
55
56
57
58
Be sure to update your `image_sampler` to scale the returned PDF according to
the Jacobian that appears when converting from one sampling distribution to the
other. The PDF value that corresponds to a pixel in the HDR map should be
multiplied by the Jacobian below before being returned by
`Samplers::Sphere::Image::pdf`.
yhesper's avatar
yhesper committed
59

TheNumbat's avatar
TheNumbat committed
60
<center><img src="figures/env_light_sampling_jacobian_diagram.png"></center>
Hesper Yin's avatar
Hesper Yin committed
61

TheNumbat's avatar
TheNumbat committed
62
63
64
65
The Jacobian for transforming the PDF from the HDR map sampling distribution to
the unit sphere sampling distribution can be thought of as two separate
Jacobians: one to a rectilinear projection of the unit sphere, and then the
second to the unit sphere from the rectilinear projection.
Hesper Yin's avatar
Hesper Yin committed
66

TheNumbat's avatar
TheNumbat committed
67
68
69
70
71
The first Jacobian scales the w x h rectangle to a 2pi x pi
rectangle, going from (dx, dy) space to (d\phi, d\theta) space.
Since we have a distribution that integrates to 1 over (w,h), in order to obtain
a distribution that still integrates to 1 over (2pi, pi), we must multiply by the
ratio of their areas, i.e. (wh / 2pi^2). This is the first Jacobian.
Hesper Yin's avatar
Hesper Yin committed
72

TheNumbat's avatar
TheNumbat committed
73
74
75
76
Then in order to go from integrating over the rectilinear projection of the unit
sphere to the unit sphere, we need to go from integrating over (d\phi, d\theta) to
solid angle (d\omega). Since we know that d\omega = sin(\theta) d\phi d\theta,
if we want our new distribution to still integrate to 1, we must divide by sin(\theta), our second Jacobian.
Hesper Yin's avatar
Hesper Yin committed
77

TheNumbat's avatar
TheNumbat committed
78
Altogether, the final Jacobian is (wh / 2pi^2 sin(\theta)).
Hesper Yin's avatar
Hesper Yin committed
79

TheNumbat's avatar
TheNumbat committed
80
81
82
---

### Tips
Hesper Yin's avatar
Hesper Yin committed
83

TheNumbat's avatar
TheNumbat committed
84
85
86
87
- Remember to use the coordinate system as outlined in Task 1!
- When computing areas corresponding to a pixel, use the value of theta at the pixel centers.
- Compute the PDF and CDF in the constructor of `Sampler::Sphere::Image`, storing them values in fields `_pdf` and `_cdf`. See `rays/sampler.h`.
- `Spectrum::luma()` returns the luminance (brightness) of a Spectrum. The weight assigned to a pixel should be proportional both its luminance and the solid angle it subtends.
TheNumbat's avatar
TheNumbat committed
88
- For inversion sampling, use `std::upper_bound`: it's a binary search. Read about it [here](https://en.cppreference.com/w/cpp/algorithm/upper_bound).
TheNumbat's avatar
TheNumbat committed
89
- If you didn't use the ray log to debug area light sampling, start using it now to visualize what directions are being sampled from the environment map.
Hesper Yin's avatar
Hesper Yin committed
90

TheNumbat's avatar
TheNumbat committed
91
---
Hesper Yin's avatar
Hesper Yin committed
92

TheNumbat's avatar
TheNumbat committed
93
## Reference Results
Hesper Yin's avatar
Hesper Yin committed
94

Hui Wang's avatar
Hui Wang committed
95
96
97
![ennis](./images/ennis.png)
![uffiz](./images/uffiz.png)
![grace](./images/grace.png)
Hui Wang's avatar
Hui Wang committed
98
99
100


You can find the environment maps in the results at https://vgl.ict.usc.edu/Data/HighResProbes/.