Since I am prototyping with stealth based gameplay mechanics, one of the most important aspects of the game is going to be how environmental queues are portrayed to the player. To start, I looked to one of my favorite developers for inspiration. The game I’m referring to is The Last of Us by Naughty Dog.
In The Last of Us there is a listen mechanic where the enemies can be seen outlined in a soft glow, even if there are obstructions between the enemy and the player’s view. I wanted to produce a similar effect so I originally created a simple sprite outline shader in Godot. I accomplished this by replicating the sprite image in either 4 or 8 directions and removing the original sprite using the flipped alpha layer. This created a simple growing based outline around any sprite.
Source code examples for the project are available here.
In Unreal, I started by creating a new actor that would contain the outline sprite for rendering and a lifetime timer. Whenever one of these actors is created, it immediately starts a timer based on how long it should exist. At the end of the timer the sprite outline actor simply destroys itself.
For the outline effect in Unreal I ended up taking it a step further than the outline shader created in Godot.
First, the sprite texture is passed into the material along with it’s dimensions. These are then fed into a Sobel Filter which uses convolution to calculate discrete vertical and horizontal derivative approximations at every point in the texture. These approximations are of the image intensity gradient and are used to detect edges in the sprite texture. The Sobel Filter is a relatively simple filter with correspondingly poor results but since I am only applying it to relatively simple 2D sprites it does the job fairly well.
The Sobel Filter node in the material graph is a Custom Expression node containing the Sobel Filter algorithm written in HLSL.
The next step is to take the output of the Sobel Filter and multiply it with the alpha channel from the original texture to remove artifacts that may have appeared. This value becomes the opacity mask for the final image.
The last step is to multiply the sprite outline by a color value so it is easier to see in the game. In the future I may extend this material to add some form of glow effect. For now though, it allows me to continue prototyping with a simple visual effect for in game sounds.
As you can see, whenever the player emits a “noise” a sprite outline actor is created at the player’s location. The outline remains where it was created until it outlives its welcome at which point it is removed from the map.
Since I am planning on allowing the player to walk behind objects that may obstruct the view of the character, I needed to make sure sounds could be seen through objects. To do this was fairly simple.
The material must be translucent, then inside of the material translucency settings the “Disable Depth Test” option must be selected. This will cause the engine not to consider the depth buffer when rendering objects that are using the sprite outline material.
The final result ends up looking like this: