Think of a scene from the last video game you played. How many objects were in the scene? If you were playing an FPS game set in World War II, there would be gun textures, environment textures, and textures used for the objects in that scene. To create visually pleasing results, we use numerous textures for every material we create. Each material is packed with albedo, roughness, cavity, metal, normal, displacement, and in some cases, opacity, among others. Additionally, imagine that you use additional roughness maps to generate imperfections. Texture count can quickly pile up, and even though we are living in the golden age of PC hardware, this many textures are still too demanding for our home PCs. So, to avoid this texture overload, we found a way to combine multiple textures and squeeze them into one texture. For example, instead of using four separate textures for one material (Normal, AO, Cavity, Displacement), we pack them into one texture and use that texture only to obtain the values we need. But how do we pack textures? That’s what I am going to talk about in this tutorial.
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.
Here, I have downloaded a brick texture from Quixel that has the ID number “brick_rough_xertbj1” if you’d like to follow along. In the folder I downloaded, we see that Quixel provided us with the following textures:
Note: You can navigate to Bridge’s settings and specify which additional texture files you wish to download. By default, cavity textures are not included.
Note: If you are using a bump map, one would typically pack a bump map as a separate texture from other maps since this allows for better organization and management of textures within the material workflow.
Switch to the ‘Channels’ panel.
Click on the ‘+’ button to create a new alpha channel.
Take your roughness map and paste it into the alpha channel we just created.
Note: Dragging and dropping the texture directly from a folder to the channel won’t work. You need to open the texture in Photoshop, select it there, and paste it.
Our texture is ready.
And we’re already done with our first texture! In the RGB channel, we store our albedo values, while the alpha channel contains the roughness info. Now, we can move on to the next step!
4. Take your normal map, go to the channels, and create an alpha again.
Bring your normal texture into Photoshop.
Create a new alpha channel.
5. Take your height/displacement map and paste it into the alpha channel.
Take your height/displacement map and paste it into the alpha channel.
Now, before we move on, we need to combine our ambient occlusion (AO) and cavity maps to paste them into the blue channel of our normal texture.
6. Open your AO map and cavity texture in Photoshop. Place your cavity texture on top of the AO texture as a new layer. The cavity layer should be above the AO layer.
The cavity layer should be above the AO layer.
7. Set the blend mode to multiply.
8. Select your cavity and ambient occlusion maps in the layer panel, and merge them into one texture.
Select your cavity and ambient occlusion maps in the layer panel.
Your advertisement can be placed here for $200 permanently. Suggested resolutions: 1800x663 or 1400x1400. Contact us.
Merge them into one texture.
Now we have an ambient occlusion map multiplied by the cavity map.
9. Now, take this newly created image and paste it into the blue channel of the normal map.
Now, the red and green channels of this texture contain normal values, while the blue channel contains ambient occlusion and cavity together. The alpha channel contains bump/displacement.
Finally, save your texture as a 32-bit TGA (Targa) file.
Ensure that the alpha channel option at the bottom of the saving window is checked so that it preserves the alpha channel.
And that’s it! If you’d also like to learn how to unpack your textures in Unreal, you can check out part two of this tutorial.
Note: Please note that if your mesh is metallic and you have a metallic texture available, you may consider using the ORM approach where you take your AO, roughness and metallic textures, stack them on top of each other and use isolate the following channels to store their values:
But I don’t recommend that approach. Rather than using this method, simply input the metallic value (0–1) directly into the master shader (If you are not using an atlas, of course.). There’s no “in-between” state for the metallic property of a material, so inside of Unreal, the ORM approach looks less appealing to me. However, it is also understandable to use it this approach if one needs it in their workflow, or wants to have flexibility for variation, artistic control or faces with shader compatibility issues in other engines. Other commonly used packing methods include: