In this assignment you will complete the lighting support and add shadow support to the viewer code you created in A1 and expanded in A2.
You will need to update your scene representation to include more light types; modify your shaders to add the 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 support to more light types; and/or add 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.
Reminder: this class takes a strict didactic, ethical, and legal view on copying code.
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.
Turn in your code in /afs/cs.cmu.edu/academic/class/15472-f24/<andrewid>/A3/
.
Your turn-in directory should include:
report/
report describing your code and illustrating that it works.
report/report.html
start with the report template and replace the "placeholder" sections.report/*.s72,*.b72
benchmarking scenes and data mentioned in your report.report/*
other files (images, animations, cubemaps) needed by your report.code/
the code you wrote for this assignment.
code/.git
your code must be stored in a git repository with a commit history showing your development process.code/Maekfile.js
build script. When run as node Maekfile.js
, produces (at least) bin/viewer
(bin/viewer.exe
on Windows), your compiled scene viewer.report/
folder; the scene file for your model should be in the model/
folder.)scene/
your created scene.
scene.s72
your main Scene'72 file.*.b72
any data files needed by your scene.*.png
any texture or lighting data files needed by your scene.scene.mp4
a screen recording (H.264 in MP4 container) of your model shown in your viewer. You may wish to rotate the view, animate the lighting, or otherwise demonstrate the scene.
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.
We will compile and run your code in an environment set up to build the nakluV tutorial -- GLFW 3.4 and the Vulkan SDK will be available.
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.
Same as A2.
This assignment uses the scene'72 (.s72
) format.
In this assignment, you may make the following simplifying assumptions about scene'72 files:
"spot"
-type lights have non-zero "shadow"
attributes.
If needed, update your code to fully support loading the "LIGHT"
type, including the "shadow"
parameter, and to deal with nodes referencing lights.
(If you've already done this, you can just point to the code in your report and get free points!)
Update the "lambertian"
and "pbr"
materials to support adding contributions direct lights and 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.
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).
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.
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.
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.
Think about how to use the lighting to emphasize a particular mood or setting.
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.
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.
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.
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 to write the report.