Assignment Goals

The primary goals of this assignment are:

  1. Add a new postprocessing pass
  2. Learn to make modifications to a large engine codebase by following similar existing code.
  3. Use a low-resolution render to speed up a computationally expensive effect.

In this assignment, we'll be using a simple single-frame technique to render clouds in low-resolution then up-res them to composite at full frame resolution. This is a bit easier than the Nubis method ofusing a history buffer of previously rendered clouds, though it does not allow as significant a reduction in the number of samples. We will render 1/4 resolution clouds each frame instead of 1/16 as Nubis does.

The single-frame method will be done in two passes. The first will render the clouds into a quarter-resolution render target (half width and half height). The second will combine the standard rendered results with an up-sampled version of the clouds. Almost all of your code this time will be modifications to the engine itself.


Postprocessing passes

Basically, you'll copy the code for an existing postprocessing pass, possibly using code from other postprocessing examples as a guide as well. I'd suggest getting your new postprocessing code to build without being hooked into PostProcessing.cpp first, then connecting the passes. You can use the vis command to check the output of you individual passes. Start with just making all the pixels some recognizable solid color then move onto making them do something useful.

Look at how existing postprocessing passes work in Engine/Source/Runtime/Renderer/Private/PostProcess. They are scheduled by code in PostProcessing.cpp. Much of the code of the postprocessing passes themeselves are boilerplate and the same or very similar for all of them. One of the simplest, at just 244 lines, is PostProcessLensBlur, with shaders in Engine/Shaders/Private/PostProcessLensBlur.usf.

PostProcessUpscale includes some high-quality upsampling, and also shows how it works to have different output size from the input size (which can work both larger or smaller). PostProcessDownsample specifically goes half-size. Most of the output size-related code is in the ComputeOutputDesc and Process member functions.

Raymarching shader

Your shader will be entirely self-contained, so will need to directly #include anything it needs (Common.ush, PostProcessCommon.ush, /Project/MaterialExtensions.ush, etc.). You still have access to everything in the View shader struct, but other data (especially from the Parameters or Primitive structs) may need to be explicitly passed in as shader variables by your postprocessing code or hard-coded in your shader. Probably the most critical of that data is the world position as the starting point of your ray. That can be computed from SvPosition using the SvPositionToWorldPosition() function. You can still render a sphere for the sky, but make it a solid color to be replaced later.

There are several ways you could use to tell what should be rendered as clouds from foreground geometry. You could look at SceneDepthZ or HZB textures with some depth threshold assuming anything far enough away is sky. You could use world position to tell if the ray start point is about the right distance from the sphere center (allowing for some numerical error in the distance calculation). You could us a color match for the color of the rendered sphere geometry.


The simplest version is to just use built-in texture bilinear filtering to get higher-resolution pixels from the low-res first pass. Use the same test for where cloud pixels are in the scene that you used for rendering to decide which pixels to replace.


Set up an assn4 scene in your class project that will demonstrate your work.

Extra Credit

Get up to 5 points of extra credit by making sure you always cast a ray if any cloud pixels in the high-resolution image might need cloud data. Otherwise you may not generate low-res cloud data in some cases when just a single pixel of the four high-res pixels wants it.

Get up to 10 points of extra credit by using a higher quality upsampling than bilinear filtering.

691 students

Nothing extra this time.


Add an "assn4.txt" with the standard description of your test computer (at least OS and CPU) and engine version (e.g. 4.17.0, 4.17.1, etc.). I have not asked for specific timings, but you can help the grader to find any partial credit if you include a short description of what you did.

I recommend committing in your UE4 repository as you go, but for submission, you should make an Engine directory in your project and copy only the modified files from your UE4 source directory there. Include a note in your assn4.txt detailing where each should be copied for us to build.

You'll need to do at least one push ("git push") of your changes to your repository on github and tag that release "assn4" so we can see your work. Since I am not asking you to submit your full UE4 engine repository, I will not be looking as much for intermediate checkins in the project directory.