Unreal Engine 4 Toon Outlines Tutorial

In this Unreal Engine 4 tutorial, you will learn how to creating toon outlines using inverted meshes and post processing. By Tommy Tran.

4.9 (21) · 2 Reviews

Download materials
Save for later
Share
You are currently viewing page 2 of 3 of this article. Click here to view the first page.

What is Convolution?

In image processing, convolution is an operation on two groups of numbers to produce a single number. First, you take a grid of numbers (known as a kernel) and place the center over each pixel. Below is an example of a 3×3 kernel moving over the top two rows of an image:

unreal engine toon outline

For every pixel, multiply each kernel entry by its corresponding pixel. Let’s take the pixel from the top-left corner of the mouth for demonstration. We’ll also convert the image to grayscale to simplify the calculations.

unreal engine toon outline

First, place the kernel (we’ll use the same one from before) so that the target pixel is in the center. Afterwards, multiply each kernel element with the pixel it overlaps.

unreal engine toon outline

Finally, add all the results together. This will be the new value for the center pixel. In this case, the new value is 0.5 + 0.5 or 1. Here is the image after performing convolution on every pixel:

unreal engine toon outline

The kernel you use determines what effect you get. The kernel from the examples is used for edge detection. Here are a few examples of other kernels:

unreal engine toon outline

Note: You’ll notice that you can find these as filters in image editing programs. Convolution is actually how image editing programs perform many of their filter operations. In fact, you can perform convolution with your own kernels in Photoshop!

To detect edges in an image, you can use Laplacian edge detection.

Laplacian Edge Detection

First, what is the kernel for Laplacian edge detection? It’s actually the one you saw in the examples from the last section!

unreal engine toon outline

This kernel works for edge detection because the Laplacian measures the change in slope. Areas with greater change diverge from zero, indicating it is an edge.

To help you understand it, let’s look at the Laplacian in one dimension. The kernel for this would be:

unreal engine toon outline

First, place the kernel over an edge pixel and then perform convolution.

unreal engine toon outline

This will give you a value of 1 which indicates there was a large change. This means the target pixel is likely to be an edge.

Next, let’s convolve an area with less variance.

unreal engine toon outline

Even though the pixels have different values, the gradient is linear. This means there is no change in slope and indicates the target pixel is not an edge.

Below is the image after convolution and a graph with each value plotted. You can see that pixels on an edge are further away from zero.

unreal engine toon outline

Phew! That was a lot of theory but don’t worry — now comes the fun part. In the next section, you will build a post process material that performs Laplacian edge detection on the depth buffer.

Building the Laplacian Edge Detector

Navigate to the Maps folder and open PostProcess. You will see a black screen. This is because the map contains a Post Process Volume using an empty post process material.

unreal engine toon outline

This is the material you will edit to build the edge detector. The first step is to figure out how to sample neighboring pixels.

To get the position of the current pixel, you can use a TextureCoordinate. For example, if the current pixel is in the middle, it will return (0.5, 0.5). This two-component vector is called a UV.

unreal engine toon outline

To sample a different pixel, you just need to add an offset to the TextureCoordinate. In a 100×100 image, each pixel has a size of 0.01 in UV space. To sample a pixel to the right, you add 0.01 on the X-axis.

unreal engine toon outline

However, there is a problem with this. As the image resolution changes, the pixel size also changes. If you use the same offset (0.01, 0) in a 200×200 image, it will sample two pixels to the right.

To fix this, you can use the SceneTexelSize node which returns the pixel size. To use it, you do something like this:

unreal engine toon outline

Since you are going to be sampling multiple pixels, you would have to create this multiple times.

unreal engine toon outline

Obviously, this will quickly become messy. Fortunately, you can use material functions to keep your graph clean.

Note: A material function is like a function you would find in Blueprints or C++.

In the next section, you will put the duplicate nodes into the function and create an input for the offset.

Creating the Sample Pixel Function

First, navigate to the Materials\PostProcess folder. To create a material function, click Add New and select Materials & Textures\Material Function.

unreal engine toon outline

Rename it to MF_GetPixelDepth and then open it. The graph will have a single FunctionOutput. This is where you will connect the value of the sampled pixel.

unreal engine toon outline

First, you need to create an input that will accept an offset. To do this, create a FunctionInput.

unreal engine toon outline

This will show up as an input pin when you use the function later.

Now you need to specify a few settings for the input. Make sure you have the FunctionInput selected and then go to the Details panel. Adjust the following settings:

  • InputName: Offset
  • InputType: Function Input Vector 2. Since the depth buffer is a 2D image, the offset needs to be a Vector 2.
  • Use Preview Value as Default: Enabled. If you don’t provide an input value, the function will use the value from Preview Value.

unreal engine toon outline

Next, you need to multiply the offset by the pixel size. Then, you need to add the result to the TextureCoordinate. To do this, add the highlighted nodes:

unreal engine toon outline

Finally, you need to sample the depth buffer using the provided UVs. Add a SceneDepth and connect everything like so:

unreal engine toon outline

Note: You can also use a SceneTexture set to SceneDepth instead.

Summary:

  1. Offset will take in a Vector 2 and multiply it by SceneTexelSize. This will give you an offset in UV space.
  2. Add the offset to TextureCoordinate to get a pixel that is (x, y) pixels away from the current pixel
  3. SceneDepth will use the provided UVs to sample the appropriate pixel and then output it

That’s it for the material function. Click Apply and then close MF_GetPixelDepth.

Note: You may see an error in the Stats panel saying only translucent or post process materials can read from scene depth. You can safely ignore this. Since you will be using the function in a post process material, it will work.

Next, you need to use the function to perform convolution on the depth buffer.

Tommy Tran

Contributors

Tommy Tran

Author

Over 300 content creators. Join our team.