A3 Lights

Out: Friday, March 15th
Due: Friday, April 5th (end of day)

In this assignment you will add lighting and shadows to the viewer code you created in A1 and expanded in A2.

You will need to update your scene representation to include lights; modify your shaders to add contribution from a list of direct lights; and add shadow map creation and sampling to solve for visibility. Your creative assignment will be to lay out and light a scene that demonstrates the lighting capabilities of your viewer.

For extra credit, you can accelerate your rendering by using a light culling/sorting pass to avoid rendering meshes with lights that do not influence them (and provide data that demonstrates how/if your culling pass is working); use advanced sampling techniques to implement soft shadows; add shadow map supports to more light types; and/or other features with instructor approval.

Scoring: this assignment is worth 15 points, total. Thanks to a convenient and intentional construction, each "point" is worth exactly 1% of your final course grade. Points are allocated as follows: A3-load is worth 2 points; A3-materials is worth 4 points; A3-shadows is worth 5 points; A3-create is worth 4 points; A3x-sort is worth up to +2 extra points; A3x-soft is worth up to +2 extra points. A3x-cascade is worth up to +2 extra points. A3x-cube is worth up to +1 extra points.

Points will be awarded for each section based on both the code and the sections of a report demonstrating and benchmarking the code.

Collaboration, Plagiarism, and Copyright

Reminder: this class takes a strict didactic, ethical, and legal view on copying code.

What to Do

Write the code to support basic light and shadow handling (A3-load, A3-materials, A3-shadows).

Use your creativity (and your code) to make something beautiful (A3-create).

Optionally, work to make lighting faster or shadows prettier (various A3x).

Demonstrate and test your code; write a report which includes screen recordings, images, timings, examples, graphs. This is non-trivial. See the report template to understand what is required.

What to Turn In

Turn in your code in /afs/cs.cmu.edu/academic/class/15472-s24-users/<andrewid>/A3/. Your turn-in directory should include:

We expect your Maekfile.js to properly build your viewer on at least one of { Linux/g++; Windows/cl.exe; macOS/clang++ }. We will not penalize you for minor cross-platform compile problems; though we would appreciate it if you tested on Linux.

When we compile and run your code, we will set the Vulkan SDK environment variables as described in the LunarG SDK getting started guide. In addition, we will have GLFW installed system-wide via apt install libglfw3-dev.

We expect your report to be viewable in Firefox on Linux. You may wish to consult MDN to determine format compatibility for any embedded videos.

Scene Format

This assignment uses the scene'72 (.s72) format. The specification of the format has been updated with light support, but should otherwise be compatible with your existing code.

In this assignment, you may make the following simplifying assumptions about scene'72 files:

Note that you may not assume anything about the number of instances of individual "LIGHT" objects! Keep this in mind when thinking about how to allocate space for shadow maps.

A3-load Light Loading

Update your code to support the new "LIGHT" type in the Scene'72 specification and add support for the fact that nodes can reference lights.

A3-materials Adding Lighting to Materials

Update the "lambertian" and "pbr" materials to support direct lights in addition to lighting environments.

Use a forward rendering approach: your scene rendering code should build a list of the relevant data for all lights in the scene and supply this data for use in the fragment shader in (e.g.) a storage buffer.

Lighting Computations

For diffuse lighting, use the observation that an above-the-horizon sphere light can be replaced with a point light with the same power located at the center of the original light. Be sure to properly attenuate the energy delivered by this light based on the distance away from the light. For the purposes of our viewer, you should assume that the light intensity inside a sphere or spot light matches the surface intensity.

For specular lighting, use the representative point idea. For sphere/spot lights, compute the point on the light surface closest to the reflection ray and use this point as the "light direction" for the purposes of evaluating the GGX specular term. For sun lights, do the same thing but use the closest direction within the light's angular diameter. In both cases, remember to normalize brightness as described in Epic's notes (you will probably have to think a bit about the right normalization factor for sun lights).

Lighting Falloff

Notice that "spot" and "sphere" lights, in addition to their physical falloff in intensity, also include a "limit" parameter which forces a non-physical additional falloff to zero at the given radius. Use a factor of \[ \max(0, 1 - (d/limit)^4) \] to implement this limit, as suggested by Epic's notes.

A3-shadows Shadows for Spot Lights

Add shadow map support for spot lights.

Your viewer should support generating shadow maps per-frame in order to allow animated lights and scenes. This will mean running several additional rendering jobs to draw scene depth into shadow map textures.

You may choose to implement an optimization that skips per-frame rendering of shadow maps in cases where it would not produce a different result.

Your code should pass shadow map samplers (and, likely, world-to-light matrices) for spot lights to the fragment shader performing lighting. Your shadow map should use at least 4-sample PCF for filtering, though you may choose to use a larger sampling kernel if you choose.

Your code should interpret the "shadow" parameter as the edge length of the shadow map to use for the light.

A3-create Light a Scene

Lay out and light a scene. You may use pre-made assets (as long as they are appropriately licensed and you cite your sources in your report) in your scene; but you should place all the lights yourself.

A3x-sort Light-Mesh Sort

Optimize rendering speed by adding a broad phase that makes sure that meshes are only rendered with lights that might influence them.

One method you might use is to make a set of spatial bins in frustum space and assign every light and/or mesh to the subset of these bins that they overlap. This avoids spending any bin space on objects/lights that aren't visible anyway.

A3x-cascade Shadow Map Cascade for Sun Lights

Add support for cascaded shadow maps to support shadows from sun lights.

You may be aided by this nice write-up on MSDN(!), despite its Direct3D focus. I also recall that this this post (part 2) from The Witness' development blog was an interesting read, though I can't speak to its helpfulness in actually implementing the technique.

Your code may interpret the "shadow" parameter as some sort of linear size related to the cascade resolution -- what, exactly, this means is probably dependant on how you choose to store your shadow map cascade.

A3x-cube Shadow Map Cubes for Sphere Lights

Add support for shadow map cubes to cast shadows from sphere lights.

Your code should interpret the "shadow" parameter as the edge length of the shadow cube to use for the light.

A3x-* Other Extra Credit

If you are inclined to add additional complexity relating to shadows or lights to your viewer, consult with the instructor for permission and an estimate of the extra credit you can earn.

Don't forget the report

Don't forget to write the report.