[Unreal] Post Process based Scopes [Part 1/3]

Video version:

This is a guide into how to implement a Post Process based Scopes. If you have experience with Unreal you know that usually how scopes are implemented is by Picture-in-Picture. There are many guides that you can find for that method in the internet.

Links to some Picture-in-Picture Scope guides:

The main problem with Picture-in-Picture scopes are they are usually very performance hungry.

In this guide, I’m introducing method that aims to be light on performance while still achieving the desired effect of a Picture-in-Picture.

Diagram on how this is achieved

Disclaimer

  • Make sure you’re familiar with Picture in Picture Scopes. This guide assumes you are familiar / have used Picture in Picture Scopes in the past.
  • This is not industry standard and an experimental implementation. It might be hard to find solutions for edge case problems.
  • Not a flawless solution, much like a Picture-in-Picture method. There are caveats and issues

Step 1: Make the post process material

In the Content folder, create a new folder named ScopePP and under that create another folder named PostProcess just to keep things tidy.

Open that, create a Material and name it M_Sight_PostProcess.

In the material node:

  1. Select the end point of the material, change Material Domain to Post Process.

Creating the Post Process of the peripheral view (outside of the scope):

  1. Create a ScreenAlignedUVs node.
  2. Create a SceneTexture node, change the Scene Texture Id to PostProcessInput0. Connect the X100%, Y100% out pinfrom ScreenAlignedUVs node to UVs in pinfrom SceneTexture node.
  3. Create a ComponentMask node, connect Color out to the mask node. In it make sure R, G, and B are checked.

Creating the Post Process of the zoomed scope area (inside of the scope):

  1. Create a ScreenAlignedUVs node.
  2. Drag X100%, Y100% pin, then create a Multiply node.
  3. Create a ScalarParameter node, name it “ZoomScale”, make the Default Value 0.5 for testing purposes. Connect the out pin to the B pin in the Multiply node.
  4. Drag the out pin from the Multiply node and create a BreakOutFloat2Component node.
  5. Drag out both the R and G out pins, create an Add node for both of them.
  6. At the end create an AppendVector node, and connect the Add nodes to it.
  7. Create a Custom node, to explain it short this allows you to create a small snippet code.
  8. In the Custom node, change the output type to CMOT Float 1.
  9. Change the description to which you like. I named mine: Calculate UV Scale Offset to Center Screen.
  10. Next, under Inputs, Index[0], change the Input Name to ScaleValue.
  11. Now on the code part. Change the code field to:
    • ((1 – x) * 0.5) % 0.5
      In code:
      return ((1 – ScaleValue) * 0.5) % 0.5;
  12. Connect the ZoomScale node to the Custom node in the ScaleValue pin.
  13. Connect the Custom node to both of the Add nodes.
Custom node properties

Now create the same Scene Texture and Append node from earlier.

  1. Copy the SceneTexture node and Mask node we made earlier. Paste them beside the Zoom Post Process section.
  2. Connect the out pin from the Append node to the UVs in pin in the SceneTexture node.

Creating the Scope Post Process Mask layer (where the magnification is on screen):

  1. Create a ScreenAlignedUVs node.
  2. Create a SceneTexture node, change the Scene Texture Id to CustomDepth.
  3. Copy an earlier ComponentMask node, this time make sure only R is checked. Connect the Color out pin to the ComponentMask pin.
  4. Drag out the ComponentMask out pin and create a Divide node. Change B value to 255.
  5. Drag out the Divide out pin and create a Clamp node. No need to change the values.

Now create a LinearInterpolate node.

  1. Connect the Non-Zoomed section output pin to the B pin of the Lerp node.
  2. Connect the Zoomed section output pin to the A pin of the Lerp node.
  3. Connect the Lerp out pin to the Emissive Color pin of the Material node.
  4. Connect the PostProcess Mask section output pin to the Alpha pin of the Lerp node.
Final post process material blueprint

Step 2: Import Demo Meshes

  1. Download the uassets in this zip file.
  2. Create a new folder named “Scope”.
  3. Right Click select “Show in Explorer
  4. In the Folder, place the uassets you downloaded.

Step 3: Setup FPS Blueprint

Add meshes to BP:

  1. Find the FPS Character Blueprint under First Person > Blueprints named BP_FirstPersonCharacter. And open it.
  2. Next Place the 2 demo mesh at the camera, here I just dragged the meshes into the blueprint.
  3. Arrange the meshes this way. The Scope Mesh is attached to the Camera. The PostProcesss Mask Mesh is attached to the Scope Mesh.
  4. In the PostProcess Mask Mesh, change Parent Socket to pip_reference. Make sure all transforms are at default.
  5. Adjust the Scope Mesh so it’s in the view of the Camera. If you’re following, make the Location: x:18, y:0, z:4.7; make Rotation: x:0, y:0, z:-90

Set SceneDepth settings:

  1. In the PostProcess Mask Mesh details:
    1. Under Rendering > Advanced > uncheck Render in Main Pass and Render in Depth Pass.
    2. Check Render CustomDepth Pass.

Add post process to BP:

  1. Add PostProcess component to your blueprint. Attach it anywhere, I attached it to the camera.
  2. Make sure Unbound is checked.
  3. Under Post Process Volume > Rendering Features > Post Process Materials:
    • Add an array element and select the Material we first created “M_Sight_PostProcess”.

Final Result

To compare

Things to Keep in Mind

  1. This implementation uses Custom Depth.
  • This implementation uses Custom Depth. This might cause some conflicts to other features that might use this same feature. There are other plugins or marketplace add-on that uses this. In the event you want to use this implementation my next point will be important…

  1. Learning about Stencil Depth and modify your implementation.
  • Learning about Stencil Depth is mandatory if you plan on implementing multiple features that take advantage of the Custom Depth feature of unreal. This is also required if you’re planning on adding special kinds of features on Scopes like Thermal as I guarantee you’ll also need Custom Depth to mask the Players with thermal.

  1. Image Quality concerns.
  • The performance advantage in this approach is great. Unfortunately, the greatest weakness of this approach is the Image Quality.
  • To elaborate how the magnification works, the zoom effect is stretching the Pixels on the screen. This means that if you push the magnification too much. The image on the scope will be unreadable.
  • It’s up to you to decide how you work around this, resolution scaling maybe? Personally, I like to play around the camera FoV in tandem with the PostProcess zoom to get a desired result.

  1. Beyond Post Process Scopes.
  • You can use this method of magnification not only on scopes. You want a little bit of magnification in a small red dot? Definitely possible with barely any performance impact. You can even design NVGs / Visors this way.

Miscellaneous References:

One thought on “[Unreal] Post Process based Scopes [Part 1/3]

Leave a reply to [Unreal] Post Process based Scopes [Part 2/2] – Portfolio: NGG Cancel reply