Alpha Masking
Validation of Correctness
I validated the correctness of my implementation by rendering objects with alpha masking
enabled and verifying that regions behind the masked areas remained visible. I also
checked whether the resulting shadows matched the expected behavior.
I used a checkerboard alpha texture to test my implementation. For fully opaque and fully transparent
regions, the visibility and shadowing were as I expected, as it can be seen above.
I also tested partial alpha masking with a semi-transparent checkerboard pattern in both dark and light
regions. The shadows from the darker areas were lighter than with a fully opaque cells, and the
shadows from the lighter areas were slightly darker than those of the fully transparent cells, which is
what I
expected. This test can be seen below.
Implementation
Files Modified
- include/lightwave/instance.hpp - I added an optional alpha texture to the Instance class.
- src/core/instance.cpp - In Instance class's intersect function, I implemented alpha masking by
randomly rejecting surface intersections based on the mean value of the alpha texture evaluated
at the surface UV coordinates.
Biggest Challenge
I encountered a time-consuming bug where, for regions with alpha masking, intersections
both before and after the masked region were also incorrectly treated as masked. This
caused those pixels to be rendered black. This was caused by me forgetting to revert the
intersections variable to its previous state when an intersection was rejected due to alpha masking.
Note: My implementations is not intended to work with shapes with alpha masked regions that intersect -
for examples with spheres, as I only required alpha masking for meshes and rectangles. For that,
intersections after an alpha masked points should also need to be considered.
Normal Mapping
Validation of Correctness
I first compared rendering a scene using a flat normal map with rendering the same scene
without any normal mapping applied. Both produced very similar results, aside
from small floating point differences.
I then applied various normal maps and rendered the scene using an AOV integrator
to visualize the shading normals, and verified that the resulting outputs matched my
expectations for the given normal maps.
Implementation
Files Modified
- include/lightwave/instance.hpp - I added the normal map as an optional texture to the Instance
class
- src/core/instance.cpp - I implemented normal mapping by first checking if a normal map is
present after an intersection.
If it is, the normal texture is evaluated at the surface UV coordinates. The resulting RGB
values are first stored in a vector, then the vector is scaled and
offset from the range of [0,1] to [-1,1]. Then the normalized vector is transformed to world
coordinates using the surface's shading frame, and is set to be the new shading normal of the
surface.
Biggest Challenge
The biggest challenge I had was forgetting to set the linear flag to
true when loading the normal textures. As a result, the normals appeared
incorrect (for example, a plane with a flat and zero normal mapping texture resulted in normals
completely
different than the plane's original normals), which led to me spending a lot of time debugging until
I figured out the problem was with
how I loaded the image textures and not the normal calculation itself.