How To Set Up Textures In Unreal Engine 5

In this tutorial, I will explain how to bring textures into Unreal Engine 5, including the new deformation technique used to apply displacement maps to meshes, which replaces the tessellation feature in UE4’s material editor.

In this demonstration, I’ll use a collection of textures called “Concrete Pavers” by Quixel MegaScans, if you’d like to follow along. But it’s perfectly fine if you want to use your own textures.

Lazy Loaded Image

Concrete Pavers Texture Collection by Quixel MegaScans

Attention: Since the release of this tutorial, Quixel Megascans has been moved to Fab, just so you know. Practically speaking, everything is still mostly the same, but some URLs I linked to Quixel may have changed, so keep that in mind.

These textures are available for Unreal Engine users for free. Please be aware that they cannot be used outside of Unreal Engine if you are not a paid member of the service. There are three ways to download these textures:

To keep everything simple, I’ll be downloading these textures via the Quixel Bridge app. Launch the app, search for the textures you’d like to download, and hit the download button. Your textures will be downloaded into the MegaScans Library folder, which can be found in “Documents”.

Note: If you are tired of watching video tutorials and would like to see more text-based tutorials like this one from me, you can support me on Patreon so I can dedicate more time to creating them.

Understanding How Textures Work (Optional Read)

When we are done with downloading our textures, we’ll see that every texture is labeled/named differently. If you already know about this subject or want to jump into the fun section as quickly as possible, you can skip this part. But I strongly suggest you to read this part if you’d like to understand how these image files work. I will try to keep this part as short as possible while providing you a general idea on how they work.


1. Albedo/Diffuse/Base Color

This type of textures provide color information.


2. Ambient Occlusion (AO for short)

To put it simply, ambient occlusion textures are used to give rendering engines information on when a light source hits the object, which parts of it should be darker and which parts of it should be brighter. In other terms, AO is used to create fake indirect shadows to achieve a more realistic look. I talked about AO maps in detail in this post if you’re interested in further reading. Typical implementation of this technique is simply mixing albedo/base color and AO textures together. In this tutorial, I’ll be showing how to perform this action inside of the material editor as well.


3. Roughness/Glossiness/Gloss

The roughness texture, as the name indicates, determines how light is scattered across the surface of your mesh. In other words, while rough parts will have less reflection, soft parts will reflect the things around your model more.


4. Normal Map

Normal maps or textures describe where there are bumps and dents existing on the surface of your mesh, by faking the way light interacts with the material’s surface.


5. Displacement Map

Displacement maps store information on additional details. To be clear, the displacement map I’ll be using in this tutorial will tell the rendering engine which stones in my pavement should have higher or lower depth relative to their surroundings. Displacement maps can also be used to fake details by baking them, but that’s another topic for another day.

Lazy Loaded Image

Your advertisement can be placed here for $200 permanently. Suggested resolutions: 1800x663 or 1400x1400. Contact us.

Let’s create our material!

A very important note before we begin: Built-In Unreal Engine Assets cannot be deformed; therefore, displacement maps cannot be applied to them. To add a displacement map to a mesh, it should be either made in another software such as Blender or generated inside of the modeling tools. If you don’t know how the modeling tools inside of UE5 are used, it is okay. I’ll be touching on this subject briefly as well.


Lazy Loaded Image

I’ll start by adding a plane to my scene. ↑


Lazy Loaded Image

Then we can right-click inside the content browser to create a new material. I’ll name my material “Pavement_Mat”. The abbreviation “mat” stands for material. ↑


Lazy Loaded Image

Now is a good time to bring in our textures. I create a new folder called “Pavement_Textures” to keep everything organized and drag the files from their current location directly into this folder. You can also use the import button at the top left corner to import your textures. ↑


Lazy Loaded Image

Before we jump into the material editor, we will need to make some adjustments. Double-click on the roughness map/texture, and this action will bring up the texture display window, as you can see in the screenshot above. On the right panel, you’ll see a section called “Texture.” Underneath this category, we’ll need to uncheck the box labeled “sRGB.” The reason why we are doing this is that we do not want to get any color information from this texture. sRGB activated textures are gamma-corrected inside of Unreal Engine. In other words, gamma correction modifies the luminance values of a texture. We want our roughness texture to provide the information we need in the rawest way possible. Set this variable to false by unchecking the box next to it, and save it. ↑


Lazy Loaded Image

The next step we need to take is opening the normal texture just as we did with the roughness map, and typing in “flip” in the search bar, which can be found at the top right corner. We’ll set the value of “Flip Green Channel” to true by checking the box next to it. Save it and close the window. ↑


Important: Just as roughness maps, displacement maps shouldn’t also be gamma-corrected.


Additional info: Textures created inside most other software direct their normals upside. In Unreal Engine, due to how the engine is coded, these elements should be facing inside. That’s why we are flipping the green channel. If your normal map looks weird in the material editor after you flip its green channel, you can re-check this button, and it should solve the problem. As I said, in most software, normals face upward, causing some glitches, but it is good to know that some other software, just like UE does, make their normals face inside. I suggest reading this post from blenderartists.org if you’d like to learn more about this subject.

How to use the material editor in Unreal Engine 5

Since we are done with tweaking our textures, now we can start creating our material.

Lazy Loaded Image

The very first window that greets us when we launch Unreal's Material Editor. ↑

Step 1: Loading the textures into the “Texture Sample” node.

Lazy Loaded Image

To be able to use our textures in the material editor, we’ll need the help of a node called “Texture Sample.” You can right-click inside the editor page and search for it to place it.Then click on the “Texture Sample” node and on the left panel, search for the texture you want to import to the editor. You can press T on the keyboard and left-click (mouse) at the same time to bring a “Texture Sample” node into the editor quickly. ↑

Lazy Loaded Image

Important note: Please ensure that the albedo/base color texture is set to color, the normal map is set to normal, and the roughness map has the value of linear-color.↑

Lazy Loaded Image

Normal texture’s “Sampler Type” should be set to “Normal”. ↑

Step 2: Final Touches for a basic texture setup.

Lazy Loaded Image

Now we’ll need a node called “OneMinus.” “OneMinus” node can be found under the “Math” category. What this node does is read the information from the “Texture Sample” node and invert it. In Unreal Engine, due to how the engine’s shader is coded, reflection/gloss/roughness maps do not provide the most accurate information without an inversion. ↑

Lazy Loaded Image

Now our basic setup should look like this. - Texture Setup In Unreal Engine 5 (Reference) ↑

As you guys might remember from the “Understanding How Textures Work (Optional Read)” section, we cannot plug the AO map into our master shader directly. We’ll need to combine it with our albedo/base color texture.

To do this, we’ll bring in a “Multiply” node. We’ll take the RGB output pin of the albedo map and plug it into the variable labeled as A. Then we’ll do the same thing for AO, but this time plugging it into the label B.

Lazy Loaded Image

“Multiply” node can be found under the “Math” category. ↑

Lazy Loaded Image

Mixing albedo/base color and AO values together. ↑

At this point, we have our basic texture setup done.

Having Maximum Control Over The Textures

In this part of the tutorial, we’ll learn how we can control the values provided by our textures.


1. Controlling AO Map Value

If you find the effects of AO map to be too strong for your taste and want to reduce its intensity or vice versa, you can right-click inside the editor and search for a node called “LinearInterpolate (Lerp)” to achieve this.

Lazy Loaded Image

LinearInterpolate (Lerp) Node (Reference). What the “Lerp” node does is take the values provided and generate new values. If you have ever used Adobe’s Photoshop, there is an adjustment layer/technique called “Curves.” This is exactly what the “Lerp” node does. It takes the values we provide, creates a curve by using linear polynomials, and constructs new data points that can be adjusted. The variable labeled as A can be used to get the original values from our AO texture. We can change the value of variable B directly inside of the material editor, or create and plug a parameter to it to have more control over this value from the outside of the editor. “Const Alpha” or “Alpha,” as it is called in the node variable, decides how much blending should be done between these (Albedo — Ambient Occlusion) two textures.↑

Lazy Loaded Image

We can edit the variable “B” and “Const Alpha” values directly inside the editor. ↑

Lazy Loaded Image

We can see here that different values have different effects in blending. The image on the left has a value of 5 for the “B” constant and 0.5 for the “Alpha” constant. The image on the right side has the default values. And in the display window, we can see how the material changes. ↑

Now it is time to explain how these values actually work and how we can have more control over them. The problem with the “Lerp” node is, we cannot edit its values from the “Material Instance Editor”. For example, whenever you need to change these values, you’ll need to launch the material editor over and over again. This may not sound counterproductive or a waste of time, but what if you have a very complex material setup? So, in order to avoid such and similar situations, it is always better to provide these values to the Lerp node via parameters. But first, I want to explain how we can scale our textures, and since we’ll be using parameters to scale our textures as well, there is no reason to explain the same action twice.


Scaling Our Textures and Creating Parameters in Unreal Engine’s Material Editor

Lazy Loaded Image

To scale our textures, we’ll be using the “Texture Coordinate” node. “Texture Coordinate” node can be found under the “Coordinates” category. ↑

Lazy Loaded Image

Now, we will bring in a “Multiply” node to be able to multiply the original value that we are getting from our texture coordinate node. If this sounds confusing, don’t worry. Everything will make sense in a few seconds. To quickly place a “Multiply” node into our editor, we can press M on the keyboard and left-click with the mouse. We’ll plug our “Texture Coordinate” (TexCoord[0] for short) node’s pin into the variable A in the multiply node, and then connect the pin from the “Multiply” node to all of our textures’ “UVs” pins. ↑

Lazy Loaded Image

Now it’s time to learn how to use parameters in Unreal Engine 5. For this, we’ll need a node called “Scalarparameter.” Right-click inside the editor or press the S key on the keyboard and left-click your mouse at the same time to quickly place it. “ScalarParameter” node can be found under the “Parameters” category. ↑

Lazy Loaded Image

Default ScalarParameter name and values. ↑

Lazy Loaded Image

Unlike most other nodes, we can actually rename the “ScalarParameter” node. I’ll rename it as “Texture_Scaler”. Then we can connect it to our “Multiply” node’s B variable. After the connection, our texture will look very blurry, as you can see in the top left corner of the screenshot. This is normal. There is nothing to worry about. This is happening because, at the moment, we are multiplying the values we are getting from our “Texture Coordinate” node by 0. And as basic math rules dictate, if we multiply something by 0, we’ll get the result of 0. We can confirm this by checking the values at the bottom left corner. (Make sure that your “ScalarParameter” is clicked/highlighted beforehand to access its values on the left panel) The values of the “TextureCoordinate” node are being multiplied by zero by our “ScalarParameter”. ↑

Lazy Loaded Image

As we can tweak these values. Underneath the “Material Expression Scalar Parameter” section, 3 variables welcome us. These variables are labeled as: ↑

  • Default Value
  • Slider Min
  • Slider Max

Default value, as the name indicates, sets the default value of the scale. If we set it to 1, we’ll see our texture back.

Additional Info: “Texture Coordinate” node has the value of 1.0 for U tiling (U direction), and the same value for V tiling (V direction) by default. More information about the subject can be found in the UE Documentation.

I’ll keep the “Default Value” variable at 1, set the “Slider Min” variable to 0.1, and the “Slider Max” variable to 10 for a varied range. You can always adjust these values based on the type of material you’re creating.

Additional Info: You don’t need to use the “ScalarParameter” node to change the values of the “Multiply” node’s B variable. You can click on the “Multiply” node to edit the values directly from inside the node. We’re using a “ScalarParameter” here because later, if we want to create a material instance, we can quickly tweak these values according to our needs without constantly navigating in and out of the material editor. Let me emphasize this again: We can’t adjust the variable values of the “Multiply” node outside of the material editor. That’s simply why we’re using the “ScalarParameter” node.


Applying What We Learned to Our Roughness Map

Lazy Loaded Image

We can follow the same approach that we used above for our roughness map as well. Bring in a “Multiply” node. M + Left Click for Quick Placement. ↑

Lazy Loaded Image

Let’s create another “ScalarParameter” node. S + Left Click for Quick Access I’ll re-name it as “Roughness_Tweaker” and feed it into my “Multiply” node’s B variable. ↑

Lazy Loaded Image

If I set the default value to 6, we are getting a very rough surface. (Demonstration Purposes Only). I’ll set my default value to 1. My value for the “Slider Min” will be set to 0, which will give us a very reflective surface, and my value for the “Slider Max” will be set to 1, which will give us the default roughness value of my roughness texture. ↑


Adjusting The Normal Map Intensity

Lazy Loaded Image

The last thing we’ll do before we start using the new deformation method to apply displacements across our mesh’s surfaces is to learn how to adjust a normal map’s intensity. To adjust our normal texture’s intensity, we’ll need a “FlattenNormal” node. “FlattenNormal” node can be found under the “Misc” category. ↑

Additional Info (Optional Read): What the “FlattenNormal” node does, without diving into too much detail, is construct the normal map’s vector components’ (XYZ) length and modify them in the way UE prefers. Some shaders don’t care if a normal map is flattened or not, but some do. There is more to explain about how it exactly works under the hood and more reasons on why we actually need it, but knowing this much about it for now will be enough. If you guys would like to learn more about it, please leave a comment. Depending on the volume I get, I might create a separate post for it.

Lazy Loaded Image

Now, I’ll plug our normal map’s pin into the “Normal (V3) Result” pin. Secondly, I’ll create another “ScalarParameter” node (I’ll be naming this one “Normal_Density_Tweaker”) so I can tweak this value outside of the material editor, and connect it to the “Flatness (S)” variable. ↑

  • Default Value: 0
  • Slider Min: 0
  • Slider Max: 1

One thing we need to be careful about with the “FlattenNormal” node is that its method of reading the values from our “ScalarParameter” node is inverted. In other words, a value of 0 means we’ll have the full density of the normal map, and 1 will mean that there is no normal map density at all.

Tip: Going beyond the value of 1 will invert the normal map. Going below zero will increase the density of the normal map.

Tip: By double-clicking on any node line, we can create a “Reroute” node. This node allows us to organize the lines between our nodes and keep everything easier to read.

Lazy Loaded Image

“Reroute” Node in Action ↑

Applying Displacement Maps In Unreal Engine 5

Before we learn how to apply displacement maps to our meshes in UE5, I want to mention a few important things that I think are essential for every UE user to know. As I mentioned at the beginning of the tutorial, you cannot deform built-in UE meshes such as cubes, planes, cones, etc.

Another very important thing to know is that UE5 has a completely new way of implementing displacements. In Unreal Engine 4, we could import our displacement texture into the material editor and activate a feature called “tessellation” from the master shader. That was simply how it was achieved in Unreal Engine 4. From UE5, the tessellation feature is completely removed. Now, when we apply our displacement texture to our mesh, it modifies the mesh itself. Let me underline this part again: We are not making any changes in the material node editor. We’re literally changing our mesh’s physical structure when we apply our displacement texture across its surface. This is important to know because if you want to use your mesh throughout your level with different displacement maps, you should make a copy of the original mesh since applying the displacement texture will change the original mesh. If this part sounds confusing to you, I’d suggest keeping reading the post until the end and checking the screenshots before trying it out yourself. Now we can move onto how we can do this.

Lazy Loaded Image

The first thing we’ll do is make sure that our “Modeling Tools Editor Mode” plugin is enabled. You do not need to download anything extra to get this plugin. It comes with UE5 by default. If it is not activated by default, please click on the category labeled as “Edit” at the top left part of your screen, select “Plugins” and search for “Modeling Tools Editor Mode.” Make sure the box next to the title is checked. ↑

Lazy Loaded Image

UE5 will prompt a text that reads: “UE5 needs to be restarted.” Hit okay. Now we are going to switch from “Select Mode” to “Modeling Mode”. You can switch between the modes by using the layers located at the top left corner. We can also just press Shift + F5 to activate the “Modeling Tools Editor Mode.” ↑

Lazy Loaded Image

Underneath the “Deform” tab, we’ll find a modeling tool called “Displace.” Make sure your mesh is selected and then click on this feature. It’ll immediately take action. ↑

Lazy Loaded Image

UE5 will prompt a new message that reads as: “Displace: Accept — Cancel” We won’t click the accept button until all of our adjustments are complete. We’ll change our “Displacement Type” from “Perlin Noise” to “Texture2D Map” since we’ll be getting our height/displacement information from our displacement texture. ↑

Lazy Loaded Image

Re-setting “Displacement Type” in action.↑

Lazy Loaded Image

Underneath the “Option” category, an area named “Displacement Map” will appear. Now we can select our displacement texture from this menu.↑

One thing we need to be extra careful about with this new deforming tech is, unfortunately, the tiling values that we set in the “Material Node Editor” cannot be accessed by UE’s in-editor modeling tools.

Lazy Loaded Image

My “TextureCoodinate” node values. ↑

Lazy Loaded Image

My “ScalarParameter” node values. ↑

As we can see in the screenshots above, my tiling is set to 1x1, and I’m not multiplying it. Therefore, I do not need to change my “UVScale” settings inside of the modeling tool.

Lazy Loaded Image

UVScale settings inside of the modeling tool. (Reference) ↑

If you scaled up or down your texture, you’ll need to adjust the values here manually.

The two most important options we need to learn how to use here are called:

  • Displace intensity
  • Subdivisions

As the name suggests, “Displace intensity” helps us adjust the intensity of the displacement texture.

Subdivision count helps us adjust how detailed we want our displacement texture to appear on the surface of our mesh. More subdivision count means more detail, but it also means a higher poly count.

Lazy Loaded Image

Displace Intensity: 10 — Subdivisions: 100 ↑

Lazy Loaded Image

Displace Intensity: 20 — Subdivisions: 100 ↑

Now if I try to hit the accept button, UE5 will throw the error of:

  • Cannot Modify Built-In Engine Asset

This is because I am using a built-in asset (Plane — in this case) in my scene. As we talked about above, we are not allowed to deform built-in meshes. I already mentioned the solution before but if I need to underline it again:

The solution is fairly simple. We either need to import our mesh from another software or create a new mesh within the modeling tools editor. If we scroll up in the modeling tools editor, we’ll see a section called “Shapes” where we can generate new shapes for our scene. I’ll drag another plane from there to my scene, apply the material we created before to it, deform it, and hit the accept button again.

Lazy Loaded Image

No error this time! ↑

Final Words

Now you can find your material in the content browser. Right-click on it to create an instance where you can easily tweak your settings.

Some More Additional Info

As I mentioned before, this new deformation method simply “sculpts” the displacement details into the geometry/mesh itself. Oh, by the way, if you’re curious about whether this new deformation method causes any seam/tiling issues, it does not.

Lazy Loaded Image

No displacement related tiling issues. ↑

Lazy Loaded Image

As we can see here, geometry of the plane that created via Modeling Editor Tools has been modified. I do not have the original mesh anymore. So be aware of that this method changes the geometry of your original mesh. ↑

I imported a basic plane mesh from Blender to double-check it, and after the displacement action was done, the mesh was modified as well.

If you have concerns about the polygons this method will generate, it seems like Nanite can handle a great amount of polygons since it uses a very optimal rendering method, but it is always good practice to be mindful of the resources you are using. I don’t want to make this post longer, so I’ll just mention a few tools that can be helpful for you:

Lazy Loaded Image

Switching to “Wireframe” mode from “Lit” view ↑

Lazy Loaded Image

Wireframe View ↑

Lazy Loaded Image

Checking Statistics (Image 1 of 2): We can activate Statistics tool by going to Tools > Audit > Statistics ↑

Lazy Loaded Image

Checking Statistics (Image 2 of 2): We can also limit the displayed statistics to one object by switching to “Selected Objects” from the menu located at top right corner. ↑

Lazy Loaded Image

Checking Resource Usage: We can activate “Resource Usage” tool by going to Tools > Resource Usage. ↑

That’s it.

I tried to explain everything in detail without overloading information and I hope it was a good read and helpful. If you think I forgot to mention about something important or if there is something hard to understand, please feel free to get in touch. I always appreciate your feedback. You can also make suggestions on the subjects that you find hard to grasp. If it is something I am knowledgeable about, I can always try to do some writing on those matters.