Assignment Goals

The primary goals of this assignment are:

  1. Start working from a source version of the game engine
  2. Make some simple changes to the engine
  3. Learn how to ray march in a shader
  4. Modify an existing rendering technique based on published details


Modify UE4 (WARNING: a fresh build takes 1-2 hours)

  1. Download a source copy of UE4
    • Join the Epic Games github group <>
    • Clone the Unreal Engine source code
      • I recommend a shallow clone. Cloning just the 4.17.1 files rather than the entire history saves about 11 GB
      • e.g. using a a command like "git clone --branch 4.17.1-release --depth 1 UE4.17"
  2. Create UE4 build files
    • Run the Setup script (only need to do this once)
    • Run the GenerateProjectFiles script (may need to do this again if you ever add or remove source files)
  3. Do an intial build
    • Open the UE4 project file (Visual Studio solution or XCode workspace, created by GenerateProjectFiles)
    • Build the UE4 editor, ShaderCompilerWorker and UnrealLightmass
    • Run the UE4 editor to make sure it worked
  4. Add a Shaders directory to your class UE4 project (alongside the Content directory) and add a file named MaterialExtensions.ush to that directory
    • Shader include paths starting with "/Project" will find files in this directory.
    • You'll need to restart UE4 for it to notice that you've created this directory
  5. Modify your UE4 to allow per-project Material shader code extensions from that MaterialExtensions.ush file, if it exists.
    • Note that I want you to make exactly these changes, so we won't actually have to take a couple of hours to compile a unique version of UE4 for each of you!
    • Add #include "/Project/MaterialExtensions.ush" to Engine/Shaders/MaterialTemplate.ush after the other #includes (around line 35)
      • This will allow you to add per-project shader functions to be read into every material for use in custom nodes
    • Make the following changes to Engine/Source/Runtime/ShaderCore/Private/ShaderCore.cpp (in diff/patch format, where - indicates lines to remove and + indicates lines to add)
      • Around line 123, immediately before the AllowDebugViewModes() function, add a new function to check for optional files to ignore
        +/** return true if file is an optional include that can be skipped */
        +bool IsOptionalInclude(FString IncludeFilename)
        +    return IncludeFilename == TEXT("/Engine/Public/PS4/PS4Common.ush")
        +        || IncludeFilename == TEXT("/Engine/Private/PS4/PostProcessHMDMorpheus.usf")
        +        || IncludeFilename == TEXT("/Engine/Private/PS4/RTWriteMaskProcessing.usf")
        +        || IncludeFilename == TEXT("/Engine/Private/PS4/RGBAToYUV420.ush")
        +        || IncludeFilename == TEXT("/Engine/Public/XboxOne/XboxOneCommon.ush")
        +        || IncludeFilename == TEXT("/Project/MaterialExtensions.ush");
      • Around line 367, in GetShaderSourceFilePath(), add a check to not complain if the path for a file it is supposed to ignore doesn't exist.
                // Make sure a directory mapping has matched.
        -       if (RealFilePath.IsEmpty())
        +       if (RealFilePath.IsEmpty() && !IsOptionalInclude(VirtualFilePath))
      • Around line 476, in LoadShaderSourceFile(), add another check to not stress if the file path for an ignored file comes back empty. Also, return a blank line then, so the line numbering on error messages will still match up (since the #include would have taken up one line too)
                        GShaderFileCache.Add(VirtualFilePath, *OutFileContents);
                        bResult = true;
        +       else if (IsOptionalInclude(VirtualFilePath))
        +       {
        +           OutFileContents = TEXT("\n");
        +           bResult = true;
        +       }
      • Finally, around line 576, in GetShaderIncludes(), replace the old test with a call to the new function-ified version
                            // Some headers aren't required to be found (platforms that the user doesn't have access to)
                            // @todo: Is there some way to generalize this"
        -                   const bool bIsOptionalInclude = (ExtractedIncludeFilename == TEXT("/Engine/Public/PS4/PS4Common.ush")
        -                       || ExtractedIncludeFilename == TEXT("/Engine/Private/PS4/PostProcessHMDMorpheus.usf")
        -                       || ExtractedIncludeFilename == TEXT("/Engine/Private/PS4/RTWriteMaskProcessing.usf")
        -                       || ExtractedIncludeFilename == TEXT("/Engine/Private/PS4/RGBAToYUV420.ush")
        -                       || ExtractedIncludeFilename == TEXT("/Engine/Public/XboxOne/XboxOneCommon.ush")
        -                       );
        +                   const bool bIsOptionalInclude = IsOptionalInclude(ExtractedIncludeFilename);
                            // ignore the header if it's optional and doesn't exist
    • This makes this file optional. If it doesn't exist, the shader compiler will just skip it rather than crash.
  6. Rebuild UE4
  7. Use this version of UE4 to open your class project
    • You can run your project directly from Visual Studio or XCode by adding the full .uproject file path to the debug command line. You can also add a second command-line argument giving the name of a map to open on startup.
    • In Visual Studio, this is under the Project Settings / Debug
    • In XCode, this is under Product / Scheme / Edit Scheme

Cloud Shapes

  1. Create a new level, Maps/assn3, with the default checkerboard floor and sky.
  2. Create a cloud map texture with at least one channel for cloud shape and one for cloud type.
    • You can use a material, shader, paint it in Photoshop or Gimp, or copy from one of the images in the Nubis presentation
  3. Replace the material on the Sky Sphere (look for the Sky Sphere Mesh in the list of components, then change its material).
  4. Create a shader for the sky sphere that ray marches through cloud shapes defined by the cloud map texture.
    • For this project, use a custom node that just passes its inputs to a shader you write in your MaterialExtensions.ush file
    • Start the march on the surface visible pixel of the sky sphere, stop when you reach some outer radius wider than the sphere
    • You may choose to shrink the sphere to put the clouds a little closer.
  5. Multiply by your noise density texture when inside a cloud.
    • I recommend creating a cloud shape function, a cloud noise function, and a combined shape and noise function.
  6. Have the noise pan or rotate to provide cloud motion.
  7. Add big and small march steps as described in the Nubis presentation.
  8. Use a straight-line raymarch for shadows for steps inside a cloud.

691 students

Use a cone of scattered shadow sample positions, as described in the Nubis presentation, rather than straightline toward the light.


Add an "assn3.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.

For full credit, you must commit multiple times during development. We'll be looking for your development process, so make sure the commit messages are somewhat meaningful. Also, by the due date, you'll also need to do at least one push ("git push") of your changes to your repository on github and tag that release "assn3" so we can see your work.