UE4

Working with Volume Textures in Unreal Engine 4 by Ryan Smith

Watch and share 2019-11-21 00-51-29 GIFs by Ryan Smith on Gfycat

Volume Texture assets are a new feature that shipped with Unreal Engine 4.21. It flew under the radar because the release notes don't mention the addition of the new feature. Fortunately, there is documentation on how to create and use them. They may not seem very useful at a glance, but they have numerous applications. I'll walk you through how to create them and show you some examples of their use.

But before we get into it, let’s take a moment to learn what a volume texture is. A normal texture is a two-dimensional grid of pixels. It has a length and a width. A volume texture has a third axis, which you can think of as a "stack" of textures on top of each other. So, if you defined a volume texture to be 32x32x16, it would consist of 16 32x32 pixel images packed on top of each other. You can put whatever images you want into a volume texture as long as they all have the same length and width dimensions. This is visualized in the image below - The transparent green represents the volume texture, and the “slices” are visualized as a “pseudo volume texture” next to it.

 
GIF taken from Ryan Bruck’s blog post.

GIF taken from Ryan Bruck’s blog post.

 

In this article, I’m going to go over how to create volume textures and show you how to apply them in various ways.

Creating Volume Textures

Pseudo Volume Textures

Creating volume textures first requires you to make a Pseudo-Volume Texture. These are 2D textures that store “slices” of a volume in rows and columns. This is visualized in the GIF below where I am creating a pseudo-volume texture which stores the density information of a sphere. The pixels that are inside the sphere are colored white, and the pixels on the outside are colored black. They are then arranged into a 2D texture that holds 3D information, hence the “Pseudo” name.

 
 

Ryan Brucks from Epic Games has a series of blog posts all about pseudo-volume textures and authoring them in UE4. I recommend reading up on Authoring Pseudo Volume Textures. There is plenty of information there that he explained very well, and I’ll be repeating some of that information in this article.

One of his posts I do want you to check out is the one on how to generate tiling noise textures. The process outlined in his post from 2016 was before the volume texture asset was available, and the method to generate and sample pseudo-volume textures was quite involved. Unfortunately, It was the only way to do it at the time. Fortunately, with the advent of Volume Textures, we get to cut out all the custom code and extra material functions that needed to be written in order to create and sample seamless tiling 3D Noise textures! It’s so much easier now. Lets explore.

Enable Volume Textures

As of 4.23, you have to enable volume textures by editing your DefaultEngine.ini file. So go to your project directory’s Config folder, find DefaultEngine.ini (if it doesn’t exist, create it). Then navigate to the Render Settings section (if you don’t see that section, you can create it) and add “r.AllowvolumeTextureAssetCreation=1”. I have an example below.

[/Script/Engine.RendererSettings]

r.AllowVolumeTextureAssetCreation=1

Create the Noise Material

For this example, let’s render some tiling Voronoi noise with 6 octaves. High quality Voronoi Noise is notoriously expensive at ~600 instructions, so it’s the perfect type of noise to cache to a Volume Texture.

Voronoi Noise.PNG

Create a new unlit material and set it up like the above image. The Noise node’s parameters can be seen in the bottom left hand part of the image.

Create a Render Target and a Blueprint for Rendering to It.

Next, create a Render Target Asset and set its size to 4096x4096 and the Render Target Format to RGBA8. Then create a Blueprint Actor and in the Event Graph, create a Custom Event and name it something like “Draw To Render Target”. Select the event node and enable “Call In Editor”. Add a “Draw Material To Render Target” node and wire it to the custom event. Reference your newly created Render Target asset in the “Texture Render Target” property, and then reference your Noise Material in “Material” property.

Draw to Render Target.PNG

Compile the blueprint and drag it into the scene and click the “Draw to Render Target” button that you should now see in the “Default” category of its Details. You should see your material drawn to the Render Target asset. If you don’t, you might have to open the Render Target asset and disable the “Alpha” channel to see what’s in there.

Generate the Volume Texture

Next, Right-click the Render Target asset and choose “Create Static Texture”. This will make a Texture object in the same folder as your Render Target asset. This “static” texture is what we use to generate the volume texture. Right-click on that bad boy. If you edited the “DefaultEngine.ini” file properly, you should see an option near the top that says “Create Volume Texture”

Doing so will make a Volume Texture asset. Name it something cool like “VT_WorleyNoise” and wait a few seconds as it processes. Open up the Volume Texture and Enable “Compress Without Alpha” since we don’t have one. This will reduce the memory footprint of the asset. Next, go to View>Viewmode and enable “Trace Into Volume” This will create a visualization of your Volume Texture that you can rotate around and play with.

Watch and share 2019-11-17 00-15-01 GIFs by Ryan Smith on Gfycat

2019-11-17_00-06-14.png

Create a Material for Testing the Volume Texture

Now that we’ve got a volume texture made, lets create a material to test it out. In order to sample a volume texture, you need to bring out a special type of sampler node called a Texture Sampler Parameter Volume. Remember, since it’s a volume texture you’ll need a float 3 for the UVs. I typically use World Space divided by a “Tile Size” parameter.

visualizer.PNG

Watch and share 2019-11-17 16-52-56 GIFs by Ryan Smith on Gfycat

When dragging the object through the scene, you’ll see the 3D change since we’re sampling from World Space. If you don’t want that to happen, sample from “Local Space” instead.

Caching the Voronoi noise to a volume texture saves us around 600 instructions for the cost of around 10MB at a 256^3 texture size. If your budget is tight, setting the maximum texture size to 128 brings the resource cost down to under 1.2MB for not that much visual difference.

Bake some Curl Noise

Don’t stop with Voronoi Noise! I also like to bake vector noises such as Perlin Curl into a 3D Texture as well. These types of vector noises store directional information that can be useful for warping UVs

Watch and share 2019-11-18 22-28-09 GIFs by Ryan Smith on Gfycat

curlnoise setup.PNG

Above is a 3D Texture of Perlin Curl Noise - I used the Vector Noise node to generate this. Getting it to tile is a bit tricky, though. I had to multiply my UVs by 6 and use a Tile Size of 36 on the Vector Noise node. You then have to remap the values into the 0 to 1 range when you bake it out. When sampling from this volume, remember to map the values back into the range of -1 to 1.

Applications

Now that you’ve got all these beautiful volume textures at your disposal. Let’s take a look at some of their applications.

Visual Effects

I love to sample these textures with a mesh’s UV Coordinates and append a Time term to the W coordinate to “push” the UVs through the Volume texture.

You can see the setup in the image below and the resulting visuals to the right. It creates a pretty cool animation that would be very difficult to recreate with 2D Textures.

example1.PNG
 

Watch and share 2019-11-20 18-57-52 GIFs by Ryan Smith on Gfycat

We can further improve visuals by sampling our Curl Noise using the same technique and using it to warp the UVs of the original noise texture to create more interesting effects. Combining multiple noises and multiple warps can produce a whole variety of visuals.

example2.PNG

Watch and share 2019-11-20 18-49-29 GIFs by Ryan Smith on Gfycat

The above shaders were all created using the techniques above with some simple adjustments to UV size and warp strength. You can go even further by panning the textures on their U or V axis. This is how the fire in the above GIF was created. It looks quite natural and it’s hard to spot any repeating elements since all of the textures are panning on multiple axes at different speeds.

Volumetric Fog

Adding a bit of texture definition to volumetric fog is another great use case for volume textures. Without the textures themselves, you’d have to use the noise nodes in your materials which can be very costly. Baking them down simplifies the cost of the shader a great deal and allows more complex effects without becoming prohibitively expensive to use. We used these all over the place on Borderlands 3.

Watch and share 2019-11-21 00-33-55 GIFs by Ryan Smith on Gfycat

In the above image, I’m using a shader that samples a warped Voronoi noise with a 3D spherical mask for use with volumetric fog. The scene was taken from the Multi-Story Dungeons kit that you can get on the UE4 Marketplace. I applied the shader to a simple sphere static mesh, which is then used to render a volume into the scene. Documentation for using Volumetric Fog can be found here. Other examples can be found on Ryan Bruck’s blog post titled UE4 Volumetric Fog Techniques. That post is a couple of years old now, and you can see the way things had to be done before the volume texture asset was a thing.

volumetric fog example.PNG

Don’t forget to set your material domain to “Volume”

Clouds

Ray Marching is an incredibly complicated and expensive technique, but it can be used to render beautiful cloudscapes like those seen in Horizon Zero Dawn, Red Dead Redemption 2, and a few other open-world games.

In fact, the technique in the video above is not possible without using a few different tiling volume textures. For more information on this technique, you can check out their paper. They also have a detailed guide on how to create this in GPU Pro 7 (Chapter 4). If I get some time, I hope to walkthrough how this effect can be accomplished within UE4.

Final Thoughts

Volume textures are easier than ever to create and work with in the Unreal Engine. With the addition of Volume Texture assets and the tools that automatically create them from Pseudo Volume Textures, you' can get up and running with them quicker than ever. I encourage everyone to integrate these textures into your visual effects and environment art pipelines. Obviously, all of the applications cannot be covered in a single post, but I hope to how everyone ends up using these. Thanks for reading!

Ryan

A Practical Approach to Creating Glass Materials for Physically Based Rendering by Ryan Smith

Watch 2019-03-24 23-05-39 GIF by @virtuosic on Gfycat. Discover more related GIFs on Gfycat

A colleague of mine recently asked me how i’d go about creating glass, so I figured I would make a walk through. We’ll start by making some grunge textures in painter and then we’ll import them into UE4. This walk through isn’t intended for beginners. As such, i’ll be skipping over some details that i’m assuming you already know.


Making the Grunge Textures

The grunge texture we’re going to make will act as a mask between our glass sub-material and our dirt sub-material. This is probably the most important part of the process because without decent grunge textures, our glass won’t look convincing. Anywhere where the grunge is applied will increase roughness, opacity, and base color resulting in the appearance of dirt on the glass.

Don’t pick a random noise or grunge to use for the dirt map. Find some textures that make sense to use on a window pane that’s exposed to the outdoors. Tell a bit of a story with it. Did the window get dirty and splattered before someone came by and tried to wipe it down? Would you see the evidence of those wipes and leaks? How about moisture? If the window was exposed to morning dew, humidity, and rainstorms, you’d definitely see some of that. Those were the questions I asked myself before starting to make some of the textures.

In the GIFs below I’m using Substance Painter’s stock noises because they work really nice for what I need. I start with a Dirt1, then add in Grunge Leak Small and then subtract Grunge Wipe Brushed to give it the look like someone tried to clean it off at some point. I then use a Perlin Noise to subtract some detail and break up the tiling a bit. I then add on some Moisture Noise. Finally I adjust levels a bit and finish up with a Sharpen. I did a similar process for the secondary grunge using similar maps. You can see that on the bottom right.

Watch 2019-03-24 19-08-14 GIF by @virtuosic on Gfycat. Discover more related GIFs on Gfycat

Watch Grunge00 New GIF by @virtuosic on Gfycat. Discover more related GIFs on Gfycat

To preview these in painter, i have a really simple setup of just two layers. Before you start, navigate over to the Shader Settings and set the shader to PBR Metal Rough with Alpha Blending. This will allow you to preview the mesh with transparency. I’ve also loaded in a flat plane oriented to the X axis for my preview mesh.

The Base glass layer has the following properties

BaseColor - 0.01 (Grayscale)

Roughness - 0.0

Metallic - 0.0

Opacity - 0.5

The Dirt layer only has 3 channels enabled and their properties are as follows:

Base Color - 0.15

Roughness - 1.0

Opacity - 1.0

I then add a black mask to the Dirt Layer and build the above textures directly in the mask stack. Result should look something like below.

If you want to create Opaque glass, simply set the opacity of the glass base to 1.

 

Watch 2019-03-24 21-20-20 GIF by @virtuosic on Gfycat. Discover more related GIFs on Gfycat

 

Building the Glass Shader

Time to pull the textures we made into Unreal and build a shader with them.

Lets first think about the properties which are relevant to physically based lighting of a completely flat pane of glass . We’ve got Base Color, Roughness, and Opacity. We don’t care about Metallic, since glass isn’t metallic. I don’t care about the normals either, since we’re building the shader for typical glass that doesn’t have bumps and grooves or warps. I’m also going to use the Spiral Blur function that comes with the unreal engine, and as a consequence of that decision, i won’t be able to use refraction, so i’m not going to worry about that for now. I can drive all of the effects above through a single packed texture map that contains the two textures I created above. One other important assumption to make here is that that this shader is designed to be used on a flat plane mesh. Adding this constraint enables us to add some cool features that will help improve its versatility.

So, I’ve created a shader. I have Blend Mode set to Translucent, Shading Model set to Default Lit and Lighting mode set to Surface Forward Shading. A warning here, using the surface forward shading is the most expensive lighting mode for translucent shaders because it calculates lighting for each light that’s hitting it, rather than using a deferred method. It also takes forever to compile so i hope you’ve got some patience. If you don’t have patience you can always just set blend mode to opaque to act as a “preview” until you need to swap back to translucent to test out the spiral blur. I’ve also enabled “Use Material Attributes” because i prefer to work that way when working on a shader that is blending multiple sub-materials.

The shader we’re going to build consists of 5 elements; We’ll first create the Glass and Dirt sub-materials just like we did in Substance Painter. We’re going to then create the grunge map expression that is the most involved part of the shader. After that we’ll hook up spiral blur and call it a day.

The final material at a glance. You can use this image to get your bearings when looking at the closeups below.

Lets first look at the Glass and Dirt sub-materials. This is a great place to start. I use Make Material attributes to set up our sub-materials because it’s just so much easier to work with when creating a shader that’s blending between two or more of them. If i didn’t use Material Attributes i’d have to blend all of the relevant attributes which would create a spaghetti node network. This method lets me keep it pretty clean.

Glass and Dirt Sub-materials

After the Glass and Dirt are set up to blend, I start to craft my Grunge Map expression. This is made up of a block of code that samples the packed grunge texture twice. The first texture (the one on top of the graph) is sampled with a slight bump offset to give the illusion of thickness to the glass pane. The second texture doesn’t have this effect. Both samplers have independent UV Tiling controls and scale based on the actor’s scale. This is accomplished by multiplying the coordinates by the Object Scale node. I’ve also implemented some functionality that you can see near at the beginning of the graph which adds a random offset to the texture coordinates whenever it is dragged 32 units in either axis in world space. This will help reduce obvious repetition in the texture in the event the planes are placed adjacent to each other. After I sample the textures i multiply them by a grunge intensity to help hone in the look i’m going for.

Grunge Map Sampling and Bump Offsetting

The inverse edge mask is a great way to break up the glass pane from the middle out to the edges. It’s just an easy tool to add to the box. You can see it’s effect bottom right.

Inverse Edge Mask to help break up glass panes if needed.

Watch 2019-03-25 00-38-25 GIF by @virtuosic on Gfycat. Discover more related GIFs on Gfycat

The mask adjustments block is a place where i add a bias so i can sort of control a minimum amount of grunge. I then multiply it by a “Master Intensity” which is essentially a master knob for the grunge intensity that happens after all the other values are nailed down. I have a bunch of saturates here to act as a sort of check on user input as well as keep the values in the range of 0-1. They’re practically free to use on modern hardware so it’s not too shitty to use them… although I may be able to get rid of one of them below but i got lazy.

Mask Adjustments

The last part of this is setting up the Spiral Blur. This expensive node ships with UE4. It samples the scene beyond the glass pane a shit ton of times and then blurs it in a spiral, which when used right gives some pretty great results. In our case, we’re multiplying the strength of the blur by our roughness parameter since it acts as a pretty good representation of our grunge mask. I’ve also got a custom Distance Mask that’s derived from Scene and Pixel depth. Subtracting Pixel Depth by Scene Depth gives us the distance of the pixel BEHIND the glass to the pixel on the glass plane. This will give a falloff to the blur based on that distance. After that setup, I follow the node’s instructions and hook the Result into Emissive Color and add the “Scene Color clamp to 0” into the opacity chain to finish everything off.

Quick tip: Use the Get and Set Material attribute nodes to quickly modify their attributes without using the big clunky “Break” material attributes node.

After all is said and done, you should have all the parameters you need to tweak yourself a cool lookin’ glass material! Try scrubbing Master Grunge Intensity back and forth. It’ll show you the range you can get from your grunge maps. Also notice the effect of the spiral blur as the grunge density increases and decreases. It does a great job at blurring the scene behind the glass when the grunge gets thick.

Watch 2019-03-24 23-02-05 GIF by @virtuosic on Gfycat. Discover more destiny2 GIFs on Gfycat

Try adding your own features or tweaking the shader to get some cool results. I really hope this walk through helps you in some way! Cheers.

Procedural Star Fields by Ryan Smith

It's tough to make a starry-night sky using textures. You either have to use very large textures to get the resolution you want, or you have to use smaller tiling textures, resulting in obvious repetitive patterns. Some people end up using a combination of both which may get the job done at the expense of precious memory.  

The longer you've been doing game development, the more you'll understand that there are countless ways to achieve a desired result. The only difference is what it costs you. Lets take a look at a way to make stars that wont cost you any texture memory. Instead, this method relies on the raw horse power of the GPU, costing us only pixel shader instructions. 

How it Works

The algorithm can be broken down into a few steps. First, generate a grid of UV Cells. Offset the UVs by -0.5 so that the origin is in the center of the cell. Use the cell to generate a radial gradient with a radius of 0.5. Them using a random vector per cell, offset the radial gradient's position and shrink the radius by double the magnitude of the random vector.

To preview the algorithm in action, left click and hold the button down on the below image, and drag your mouse left and right. You'll see the basic steps of the algorithm animate as you move your mouse further to the right of the image.

 

Below is another shader example, this time with a smaller scale and 8 iterations. Drag left to right to watch the offset happen. You can also enter fullscreen mode by pressing the square bracket button on the bottom left. 


A Small Look at Generating Random Noise

At the heart of pretty much all noise generators is a function that creates pseudo random noise.  The function i'm using in the above examples comes from David Hoskins's awesome Shadertoy example. I use the "hash22" function, where the "22" means that the function takes a 2D value as an input and returns a 2D value. The  below method is how i "look up" random values per UV Cell. There are many different ways to generate random noise, I encourage you to read up on these methods since they're an important step to many procedural effects. 

Making it work in the Unreal Engine

To make the algorithm work in UE4, we need to implement a version of the noise that works in 3D. The above shaders work with 2D, but it's easy to change it to support 3D. All you have to do is provide a 3D coordinate as an input, and make sure you have a 3D cell noise, the rest of the instructions are the same. Thankfully, UE4 has the Vector Noise node, which defaults to the Cell Noise type. 

In Unreal, I apply the shader to a inverted sphere with a radius of 50 units.

Procedural Star function graph. UE4

The above graph can be considered a single iteration. In this post's cover image, i'm using 3 iterations, each one having a different grid scale and brightness. Check out the results below. 

Watch this GIF on Gfycat. Discover more GIFS online at Gfycat.

That's pretty much it!  I encourage everyone to figure out different ways to make use of this effect other than stars. Thanks for reading.