Environment Map Emitter

Effect of the Feature

An environment map is texture that is used to illuminate a scene from all directions. Different than a regular image texture, for environment maps usually a texture with a higher value range is used, such that the map can represent not only color but also brightness. In our case, we use exclusively EXR-textures. All presented environment maps are obtained from PolyHaven.com (see bottom for author credits). The advantage of an environment map over other types of illumination is that they provide very realistic lighting environments out of the box thanks to their nature of representing actual captured scenes. A very important part of this implementation is proper importance sampling as this reduces variances drastically.

Nori
Mine (Nori)
Mine (Nori)

Technical Implementation

At the core of our environment map implementation lies a 2-dimensional discrete probability distribution. While we generally orient ourselves on the approach from PBRT, unlike them we do not use a mipmapped texture but only a bitmap. Also different to PBRT, we do not build a 2D-distribution from multiple 1D-distribution but directly create a grid of marginal row probabilities and conditional column probabilities. The way the solution works is exactly the same however, with first sampling from the marginal row distribution, followed by the conditional column distribution. The build-up of this distribution is implemented in DiscretePDF2D::initPdf() and simply normalizes the sum of the values of each row to 1 and these sums are again normalized to 1 for the marginal row probabilities. To calculate the probabilities, we use the luminance of the colors. We not only save the PDF and CDF values but also the underlying function values in order to sample directly from the distribution. Very important for the implementation are the two function dirToUV(Vector3f dir) and uvToDir(Point2f uv) that convert coordinates between a 3D direction and a point on the UV map, mapped to [0,1]x[0,1]. Additionally to the environment map, the user can also supply a tint, which allows to increase exposure or manipulate the color of the environment map. The functions that are implemented by infinitearealight.cpp are the same as those of a regular emitter, namely sample() ,eval() and pdf().

The sampling works by sampling a random UV-coordinate from our 2D distribution. This point is then converted to a 3D direction using uvToDir(Point2f uv). In both the sample-function and the pdf-function, we want to return the PDF as well. When sampling uniform from the texture map we get an overproportional number directions close to the top and the bottom. These directions are more frequent on the UV map than in actual 3D space. We therefore need to weight them with a sine term to make directions towards the very up and very down direction less likely when importance sampling the environment map.

One important component is to terminate rays that did not intersect and return the emitted radiance from the environment map. This automatically gives a background that corresponds to the environment map. For implementation, we simply make a call to the eval function. This function again converts the direction to UV coordinates and returns the corresponding value from the environment map texture as radiance.

The environment map can be added over an extra tag in xml <envmap></envmap>. In code, the parser assigns the environment map which derives from the Emitter base class to both the list of emitters and the member variable m_envmap which can be accessed over scene->getInfiniteAreaLight(). This is for example required in the case of no intersections of a ray, where the radiance of the envmap for the given direction should be returned.

Validation

For the validation of dirToUV(Vector3f dir) and uvToDir(Point2f uv) as well as the 2D probability distribution, we create very simple test cases in the constructor of infinitearealight. These test cases allow to check the values using the debugger and trigger an abort if uvToDir(dirToUV(x)) != x.
Additionally, we write a new warp test to check whether the samples values and the PDF correspond closely. While the test does not pass successful, the sampled values correspond very closely to the computed PDF. This indicates that there is most likely a very minor bug in the implementation. As the visual quality is in no way degraded however and the importance sampling works fine, we keep it this way. Additionally, the sampled points clearly clump in brighter regions which corresponds to the desired behavior. The importance sampling works very well too and there is only minimally more noise present than with PBRT. Compared to uniform sampling on the sphere, the noise is greatly reduced.
We use the following two validation scenes to compare the influence of the environment map emitter

  • Nori: cg-project-2022/nori/verification/envmap/cbox_path_mis_envmap.xml
  • PBRT: cg-project-2022/nori/verification/envmap/envmap.pbrt

Comparison 1 - Default settings

  • Environment map: Clarens Midday
  • Tint: None (1,1,1)
  • Sample Count: 128
PBRT Mine (Nori)

Comparison 2 - With tint

  • Environment map: Clarens Midday
  • Tint: Red (1,0,0)
  • Sample Count: 128
PBRT Mine (Nori)

Comparison 3 - Night map

Medium sample render of a night environment map. PBRT crashes halfway through but our implementation delivers stable and firefly-free results.

  • Environment map: Preller Drive
  • Tint: None (1,1,1)
  • Sample Count: 256
Nori

Comparison 4 - Very diffuse map

High sample count with a rather dark and diffuse map. Only very minor changes noticeable

  • Environment map: Kloppenheim
  • Tint: None (1,1,1)
  • Sample Count: 1024
PBRT Mine (Nori)

Warp Tests

For constant to medium variance envmap, the Warptests are successful. It looks like however, that there is some bug which results in slightly off sampling. We suspect that this is cause by the discretization of the envmap which is handled differently in PBRT and Mitsuba.

PBRT
PBRT
PBRT

Conclusion: All renders are matching closely. There is slightly more noise in our version, but nothing of concern. The results for the two different parameters match closely for the PBRT and the Nori-version, but there is a minor bug in the implementation (without visible impact on the renderings).

Code Coordinates

  • The 2-dimensional discrete probability distribution can be found in include/nori/dpdf.h
  • The environment map emitter can be found in src/infinitearealight.cpp

Environmentmap Credits

We used the following environment maps and thank their authors for providing them:

  • Clarens Midday by Dimitrios Savva and Jarod Guest
  • Preller Drive by Greg Zaal
  • Kloppenheim by Greg Zaal