A1 Scene Viewer

Out: Monday, February 2nd
Check-In: Wednesday, February 11th (1hr before class)
Due: Monday, February 16th (1hr before class)

In this assignment you will build the core of a real-time scene viewer which renders scenes using the Vulkan API. This code serves as a foundation that you will modify, extend, and improve for the rest of the semester.

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: A1-load is worth 2 points; A1-show is worth 3 points; A1-cull is worth 2 points; A1-move is worth 2 points; A1-test is worth 3 points; A1x-fast is worth 1 point + up to 1 extra point; and A1-make is worth 2 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

We grade on evidence, so -- as you complete the tasks described below -- you also need to create a report that proves you have completed them successfully. This report should include screen recordings, images, timings, example scenes, and graphs sufficient to convince us that you have completed the tasks.

The report should be written in HTML in the style of the report template. Do not use a fancy HTML editor, just use a text editor.

Starting with your codebase from the nakluV tutorial, write code that can:

Stress-test your code:

Use your creativity (and your code) to make something beautiful:

A final reminder: developing the report is a non-trivial part of the assignment. Do not neglect it. Build it as you build your code.

What to Turn In

Turn in your code in /afs/cs.cmu.edu/academic/class/15472-s26/<andrewid>/A1/. (If you are accessing AFS via an andrew machine, you may need to aklog cs.cmu.edu to acquire cross-realm tokens.)
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.

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.

Check-In

For the Check-In, present evidence (in the appropriate thread in course Zulip) that you have completed A1-load and A1-show. You may re-use this evidence in your final report.

Completing the check-in is worth 2pts, one point each toward A1-load and A1-show.

Allowed Libraries

Although one of this class's principles is "No Magic," we cannot open every black box; so you are allowed to use a few approved libraries for specific tasks in your code. (These libraries are in addition to GLFW and the Vulkan SDK which -- as we note above -- will be available in our build environment.)

If you use any of these libraries, you will need to include the relevant code in your turn-in repository. We suggest a git submodule.

If you would like to use a different library for one of these tasks you do need approval from course staff (there will be a Zulip thread). Approval may not be given for certain libraries, and may take some time.

Command-Line Arguments

Some of the features you implement in this assignment are controlled by command-line arguments. Many of these are documented in more detail in the sections below. The "optional" and "required" tags indicate whether the argument is required on the command line, not whether it is required that you implement it.

You may also add your own, additional, command line arguments; indeed, there is a section in the report template to document them.

Scene Format

This assignment (and subsequent assignments) will use scene'72 (.s72) format.

In this assignment, you may make the following simplifying assumptions about scene'72 files — though your code should strive to fail gracefully if they are violated (e.g., by ignoring/skipping extra data instead of crashing):

A1-load Scene Data Structures and Loading

When launched with the command-line option --scene filename.s72, your viewer should load a scene in Scene'72 format from the file filename.s72.

Suggestions:

Warning: consider the Scene code from 15-466 as an anti-example! It only handles tree-structured scenes, isn't built for efficient traversal, and is pretty closely tied to OpenGL.

A1-show Scene Display

Now that you've loaded the scene, it is time to show it.

This will involve traversing the scene and sending each mesh + transformation to the GPU using the Vulkan API. You should be able to start with your code from the nakluV Tutorial, which is already set up for drawing object instances.

Cameras

Your viewer should have three camera modes:

If started with the command-line option --camera name your viewer should launch in scene camera mode with the camera named name active. If the named camera does not exist in the scene, your viewer should print an error message and exit.

Otherwise, it is up to you to determine the details of how to activate and switch between scene, user, and debug camera modes. (Please document how in your report.) Some handy controls might include warping the user camera to the current scene camera; setting the debug camera to a position that can see the whole scene; and toggling the debug bounding box / frustum lines.

Materials / Lighting

As per the assumptions above, all materials in your scene will be lambertian, and the only lights in the scene will be a distant directional light and/or a hemisphere light.

Therefore, your fragment shader will probably do something like this:

	vec3 energy =
		  SKY_ENERGY * (dot(n, SKY_DIRECTION) * 0.5 + 0.5)
		+ SUN_ENERGY * max(dot(n, SUN_DIRECTION), 0.0);
	outColor = vec4(texture(ALBEDO, texCoord) / 3.1415926 * energy, 1.0);
Basic hemispherical lighting equation in glsl syntax, where: n is the per-pixel normal (remember to normalize after interpolation!); texCoord is the interpolated texture coordinate; *_DIRECTION are uniforms giving the light directions; *_ENERGY are uniforms giving the light energy in appropriate units; ALBEDO is the albedo texture (here divided by pi to ensure energy conservation); and outColor is the value that gets written to the framebuffer.

A1-cull Culling

The fastest triangle to render is the triangle you don't need to render. It's time to update your viewer to perform view frustum culling. When frustum culling is active, your code should check whether a mesh instance is visible before sending it to the GPU for drawing.

In order to perform a fast visibility test you should build a bounding volume for each mesh and check whether this volume intersects the viewing frustum. Use local-axis-aligned bounding boxes for your first implementation; you may test other shapes later for potential performance improvement.

When your viewer is run with the --culling mode command line option it will start with a given culling mode selected. The modes are as follows:

We are using a culling flag because, in your report, you will need to demonstrate that culling is working, and show scenes where it has both a positive and negative impact on frame rate.

Note: as mentioned above, when rendering with the debug camera, do culling as if rendering for the previously-selected (user or scene) camera. This can be very handy for checking to see if culling is actually working! (And demonstrating that it is working in your report.)

Note2: implement a complete box-frustum intersection test (whether via separating axis or some other method of your choosing). Think about what the hard cases for such an intersection test are and how to show -- in your report -- that you've handled these cases. Remember that it's okay to discuss such things with your classmates; credit them if you do.

A1-move Animation

It is finally time to stop deferring animation. Update your parsing code to read "DRIVER" objects; add code to your main loop to track and update the current playback position for the animations; and patch in keyboard control to pause/unpause/restart the animations.

Note: the animation playback position for the first rendered frame should be 0, and should be advanced for subsequent frames by measuring the elapsed time from the first frame. (Or, in headless mode, using the times from the AVAILABLE events.)

Note2: your viewer should, by default, start with any scene animations playing and with the playback position at time 0. For the purposes of debugging/testing, you may wish to add command line options to start paused, set starting time, and/or loop animations.

A1-test Bottleneck Hunting

This part of the assignment depends on headless operation, as per nakluv Step 6a. That is, when the --headless command line flag is passed, your code should read AVAILABLE <dt> [filename.ppm] events from standard input, advance time by dt, render a frame, and save that frame to filename.ppm (if a filename is given).

Your goal in this section is to develop scenes that bottleneck in your renderer on either the CPU or the GPU.

Your CPU-bottlenecked scene should show clear performance sensitivity to a CPU-based part of the rendering workload. You will need to demonstrate this in your report by showing that performance changes when you adjust some parameter of your scene that increases CPU work without influencing GPU work.

Your GPU-bottlenecked scene should have performance sensitive to a GPU-based part of the rendering workload. You will need to demonstrate this in your report by showing that performance changes when you adjust some part of your scene that doesn't change CPU work but does change GPU work.

Any attempt on this section -- make some scene and collect some data -- will earn you 1pt. For a full 3pts of credit, you must successfully demonstrate both a CPU-bottlenecked scene [+1pt] and a GPU-bottlenecked scene [+1pt].

Note: we are intentionally vague about what sort of test scenes may work here. We will brainstorm in class, and you are also encouraged to discuss with your classmates. Please give credit in your report.

Note: there are at least three ways to generate a scene parametrically -- you could build the scene directly in your viewer using a custom command-line option; you could write a script to build the scene in Blender and then use the s72 exporter; or you could write a script to create a custom s72 file. If you choose to write code that makes a scene directly in your viewer's internal representation, please make sure that the scene could have been represented in standard s72 format -- do not, for example, have a special very expensive material type that runs a time-wasting shader.

A1x-fast Extra: Go Fast

Note: this section is work 1 point + up to 1 extra point. I tagged it as "extra" because you can skip it entirely and still receive 14/15 = ~93% on the assignment. On the other hand, if you try (and document) several substantial approaches to improving your viewer's rendering speed you can earn some extra credit here.

Within the framework of this basic viewer there are a ton of ways to (attempt to) make your code go faster. The final segment of this assignment is an open-ended exploration of these possibilities.

To receive one point on this segment, you may add any of the following to your system (and document the impact in your report):

To receive up to one extra point, go beyond by attempting more items from the list above or developing and documenting other substantial improvements of your own devising.

Don't forget the report

Don't forget to write the report.