Creating Snow Trails in Unreal Engine 4
In this Unreal Engine 4 tutorial, you will learn how to create deformable snow trails using a scene capture and render targets By Tommy Tran.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Creating Snow Trails in Unreal Engine 4
25 mins
- Getting Started
- Snow Trails Implementation
- Capturing From the Bottom
- Creating the Depth Check Material
- Creating the Scene Capture
- Setting the Capture Area Size
- Storing the Capture Size
- Deforming the Landscape
- Projecting the Render Target
- Using the Render Target
- Creating Persistent Trails
- Creating the Persistent Buffer
- Writing Back to the Capture
- Moving the Capture
- Moving the Capture in Discrete Steps
- Moving the Persistent Buffer
- Where to Go From Here?
Using the Render Target
Let’s start with blending colors. To do this, simply connect the 1-x to the Lerp like so:
Now when there is a trail, the ground’s color will be brown. If there is no trail, it will be white.
The next step is to displace the vertices. To do this, add the highlighted nodes and connect everything like so:
This will cause all snow areas to move up by 25 units. Non-snow areas will have zero displacement which is what creates the trail.
Click Apply and then go back to the main editor. Create an instance of BP_Capture in the level and set its location to (0, 0, -2000) to place it underneath the ground. Press Play and walk around using W, A, S and D to start deforming the snow.
The deformation is working but there aren’t any trails! This is because the capture overwrites the render target every time it captures. What you need here is some way to make the trails persistent.
Creating Persistent Trails
To create persistency, you need another render target (the persistent buffer) to store the contents of the capture before it gets overwritten. Afterwards, you add the persistent buffer back to the capture (after it gets overwritten). What you get is a loop where each render target writes to the other. This is what creates the persistency.
First, you need to create the persistent buffer.
Creating the Persistent Buffer
Go to the RenderTargets folder and create a new Render Target named RT_Persistent. For this tutorial, you don’t have to change any texture settings but for your own project, make sure both render targets use the same resolution.
Next, you need a material that will copy the capture to the persistent buffer. Open Materials\M_DrawToPersistent and then add a Texture Sample node. Set its texture to RT_Capture and connect it like so:
Now you need to use the draw material. Click Apply and then open BP_Capture. First, let’s create a dynamic instance of the material (you will need to pass in values later on). Add the highlighted nodes to Event BeginPlay:
The Clear Render Target 2D nodes will make sure each render target is in a blank slate before use.
Next, open the DrawToPersistent function and add the highlighted nodes:
Next, you need to make sure you are drawing to the persistent buffer every frame since the capture happens every frame. To do this, add DrawToPersistent to Event Tick.
Finally, you need to add the persistent buffer back to the capture render target.
Writing Back to the Capture
Click Compile and then open PP_DepthCheck. Afterwards, add the highlighted nodes. Make sure to set the Texture Sample to RT_Persistent:
Now that the render targets are writing to each other, you’ll get persistent trails. Click Apply and then close the material. Press Play and start making trails!
The result is looking great but the current setup only works for one area of the map. If you walk outside of the capture area, trails will stop appearing.
A way to get around this is move the capture area with the player. This means trails will always appear around the player’s area.
Moving the Capture
You might think that all you have to do is set the capture’s XY position to the player’s XY position. But if you do this the render target will start to blur. This is because you are moving the render target in steps that are smaller than a pixel. When this happens, a pixel’s new location will end up being between pixels. This results in multiple pixels interpolating to a single pixel. Here’s what it looks like:
To fix this, you need to move the capture in discrete steps. What you do is calculate the world size of a pixel and then move the capture in steps equal to that size. Now each pixel will never end up inbetween other pixels and therefore no blurring occurs.
To start, let’s create a parameter to hold the capture’s location. The ground material will need this for the projection math. Open MPC_Capture and add a Vector Parameter named CaptureLocation.
Next, you need to update the ground material to use the new parameter. Close MPC_Capture and then open M_Landscape. Modify the first section of the projection math to this:
Now the render target will always be projected at the capture’s location. Click Apply and then close the material.
Up next is to move the capture in discrete steps.
Moving the Capture in Discrete Steps
To calculate the pixel’s world size, you can use the following equation:
(1 / RenderTargetResolution) * CaptureSize
To calculate the new position, use the equation below on each position component (in this case, the X and Y positions).
(floor(Position / PixelWorldSize) + 0.5) * PixelWorldSize
Now let’s use those in the capture Blueprint. To save time, I have created a SnapToPixelWorldSize macro for the second equation. Open BP_Capture and then open the MoveCapture function. Afterwards, create the following setup:
This will calculate the new location and then store the difference between the new and current locations into MoveOffset. If you are using a resolution other than 256×256, make sure you change the highlighted value.
Next, add the highlighted nodes:
This will move the capture using the calculated offset. Then it will store the capture’s new location into MPC_Capture so the ground material can use it.
Finally, you need to perform the position update every frame. Close the function and then add MoveCapture before DrawToPersistent in Event Tick.
Moving the capture is only half of the solution. You also need to shift the persistent buffer as the capture moves as well. Otherwise, the capture and persistent buffer will desync and produce strange results.