How to match Substance Painter viewport with UE5 ? (LUTs, Gamma and many more things to learn about)

Alexandre Alves
17 min readAug 20, 2023

--

Comparison between Substance Painter with the LUT and UE5

Today, the 3D production pipeline can contain a lot of software. As much as the geometry is rather standardized between the software, the visual rendering of the objects is much more variable depending on the software used and the stage of production at which we are.

A texturing artist will rarely (if ever) work in the final rendering software and yet it is with this rendering that the result of his work is judged. Obtaining the same rendering between the different production software makes it possible to make fewer round trips due to the different nuances of the rendering engines and those used by texturing. The result is that we can devote more time to the creative part.

There are a lot of reasons why renders are different and a lot of software, but here I’m going to focus on color rendering between Substance Painter and Unreal Engine 5.

Figure 1 — Substance Painter and Unreal Engine logos

I will explain just below a very simple method to apply to have the same color rendering between these two software and for those interested, how I arrived at this result.

The existing and why it didn’t work out for me

I recently made an end-of-year short film using Unreal Engine 5 because it makes it easier to iterate the lights and have faster renders, which helps when you have short deadlines and uncertainties about your ability to produce.

One problem I’d run into on smaller projects with UE5 is that textures made in Substance Painter could look very different in the game engine. This caused us to go back and forth between the software to obtain the desired rendering and this time could have been used to refine or add other assets to the project.

First, it is necessary to ensure that grayscale textures are not sRGB in Unreal because it distorts values such as the brightness of an object. This is a topic that I discuss a little further in color spaces.

But the colors are also different, my research led me to the superb work of Brian Leleux: https://bleleux.gumroad.com/l/lHiVg

Figure 2 — Gumroad vignette by Brian Leleux

He had set up a method for older versions of Substance Painter and Unreal in order to have a close rendering. But I still found differences in some cases and I found the method quite cumbersome since it was necessary to activate a post-processing in addition to color correction. In addition, with UE5, he advised to make changes in the game engine to have similar results.

That’s why I decided to conduct my own research on the subject with these goals:

· Have the closest possible rendering for UE5

· Minimize the work that needs to be done to achieve a similar rendering between Substance Painter and Unreal

· Make changes only in Substance Painter

Before explaining how I got my results, I put here the link for those who don’t want to read about it : https://alexandrealvesdb.gumroad.com/l/ue5_lut

By going to this link, you will find the color profile to add in Substance Painter as well as how to do it. I also strongly advise you when you create a new Substance project to use OpenColorIO as your color management so that you have control on the color spaces of your textures. (You’ll understand why later in the article)

The LUT is to be used with either the default color management of Substance or the sRGB display if you use OpenColorIO for the color management. (ACES sRGB gets you closer to UE5 but not as close as sRGB + LUT in my tests)

If you don’t especially want the default UE5 Look in Unreal, you can use OCIO files to match all your software displays. Using it in Unreal disables the tone mapping that comes out of the box.

Of course, the rendering will only be the same if you have the same lighting/HDRI between the two engines so try to have an HDRI close to the final lighting of your object if it is possible otherwise try to work with a neutral HDRI.

Figure 3 — Comparison of Substance render with LUT and Unreal

The method

Preparation

Why are rendering engines different?

A rendering engine, there are plenty and very different ones. There are real-time engines that are more for games and whose goal is to get enough frames per second for it to be smooth. And pre-computed engines that take a very long time to calculate an image but take many more parameters into account and give more impressive results.

Each engine, even within the same type, can calculate things differently, work in different color spaces, or even sometimes apply transformations directly to the image to achieve a more satisfying result faster. It’s like a screen, they all do more or less the same thing but with some differences between them according to their specialty.

Unreal Engine 5 is a real-time engine that has a tone mapper applied by default (and that can be disabled even if it is not necessarily proposed), that is to say a kind of filter on top of the base image that gives a filmic aspect to the renderis. And it is the small differences between UE5 with its tonemapping and Substance Painter that we will correct.

Color spaces, gamut, and transfer function

Before moving on, I must at least explain the notion of color space since we will work with color. A color space is the color space with which we work in software. The reddest red is not necessarily the same between these spaces and the same for the other primary colors.

Figure 4 — Different color spaces

Color space is everything inside the triangle. You are not necessarily likely to see the difference because standard screens are mostly able to render sRGB. The ability of a screen to render a set of colors, we call it its gamut. And often standard screens have a gamut that covers 99% of the sRGB space.

You also have to pay attention to what is called the sRGB transfer function , which is how brightness is interpreted when using this color space. It’s also called gamma and I’ll talk about it later in more detail.

But this is what can cause problems in Unreal Engine for roughness textures for example because by default, everything is in sRGB for it while textures in grayscale are linear. That’s why you have to disable it when you import these kinds of textures.

Figure 5 — The red curve represents the encoded brightness at the input and the displayed brightness at the output

How do I compare the two engines?

To be able to compare renders effectively, you must be in similar conditions between the two engines. Here, we will use the same object and we will make sure to have exactly the same neutral lighting in both engines in order to be able to see the fundamental differences between the two software.

We assume that by using the same HDRI between the two then we are in similar states. For my tests, I made sure that the exposure was manual with a value of 10 in the Post-Process Volume in Unreal.

I modeled and textured for the occasion, a color chart that allows you to study the differences in brightness and colors between the two engines, you can get it here: https://alexandrealvesdb.gumroad.com/l/colorchart

Figure 6 — Color chart (https://alexandrealvesdb.gumroad.com/l/colorchart)

Once we have the same object with the same lighting and the same point of view, we will be able to compare accurately. And since the chart contains 24 colors, this makes it possible to compare in a wide range of cases with a single object.

HSL (Hue, Saturation, Luminosity/Lightness)

So now, we open Photoshop and to compare the colors as well as possible, we go from RGB to HSL for the color chart and also in color wheel. (The color wheel is a preference but it is very practical)

Figure 7 — Color wheel (Polar coordinate system)

We use HSL rather than RGB because it is much simpler to describe a color in terms of hue, saturation (or chromacity which represents the “purity” of the hue) and brightness (lightness) than to have to say a mixture of primary colors on a scale of 0 to 255. Thank you Munsell.

Especially since we will use a Photoshop blending mode that if the colors are the same then the brightness is at 0.

Import into Photoshop and LUTs

Once we have our two images aligned in Photoshop, we will be able to create a lookup table.

LUT

A LUT is a kind of table that will transform an image by looking at the input pixels and depending on the LUT and the pixel, the output pixel will be different.

You’ve used LUTs before, Instagram filters are an example of LUTs. So today, it’s our turn to create our UE5 filter for Substance Painter.

Figure 8 — Comparison between Substance Painter without and with LUT

We will apply a set of transformations to the image coming from Substance Painter to obtain the rendering of Unreal Engine and then we will create a LUT to apply these transformations to the viewport of Substance Painter.

We have several ways to compare images with the different blending modes of Photoshop but the one we will use is the one of difference. The more similar the two colors, the closer we get to black.

Why Difference blending mode and not Subtraction mode? The subtraction mode will reduce the negative values to 0 while the difference mode will subtract the brightest pixel by the least bright. This allows us not to lose information in some cases.

I decided that if we arrive below 5% brightness in difference, we can say that the color is close enough for this to be valid. Because there are always small differences that if we try to be too precise, as soon as we change the situation, the gap will become too big and we want something quite universal.

Exposure, offset and gamma

We always start by changing the overall parameters before tackling the details, from the simplest to the most complex.

So I started with the bottom line which just represents gray values, this will allow us to calibrate our brightness curve.

The easiest way to observe the brightness values is the HSL (Hue, Saturation, Brightness) or HSV / HSL in English, the values range from 0 to 100 which makes it easier to manipulate the values. In RGB if there are slight differences in colors, it is necessary to average the three values that will then be different, which complicates the task unnecessarily.

The darkest value and the lightest value are used to know the exposure as well as the gamma. (And put all adjustment layers as clipping mask on the Substance Painter layer otherwise it will change our reference image and it won’t work)

Figure 9- Basic difference between the two engines

Gamma (γ)

Historically, cathode ray televisions used electron beams to create images. We humans like what is simple so when describing shades of gray, the easiest way is to make a scale from 0 to 100. When the image is black, we will say that it is 0 since we do not need energy and 100 when we want white.

The problem is that our linear scale like this one to describe shades of gray does not correspond to what was happening in the cathode ray TV. Because the behavior of brightness as a function of voltage is not linear.

Figure 10 — Linear curve vs power function curves

Today, cathode ray televisions are disappearing (and they have already disappeared in many places) but we have kept this notion of gamma. What for? For the sake of compatibility with existing images and equipment. Our current screens have the job of compensating for the gamma of the images to reproduce something linear in output.

For those who are not familiar with these notions of input and output, imagine that for each pixel of our image, we give it a value between 0 and 1 of brightness.

With the linear curve, you will have the same pixels in output (vertical axis) as in input (horizontal axis) so your screen will display the same as before. Because with this curve, 0.8 input gives 0.8 output.

While with the Gamma curve 2.2, 0.8 input gives 0.6 output.

Figure 11 — Linear transformation
Figure 12 — Transformation with Gamma 2.2

It turns out that this nonlinear brightness curve is also found in the way we perceive brightness, our eye perceives variations in dark tones better than in highlights. That’s why if you do a linear brightness scale, it doesn’t seem to be correct.

Figure 13 — Linear scale (top) and scale following a gamma of 2.2

What must be remembered is that a gamma is a curve that defines how the brightness of an image will behave according to the input values and that our eye does not perceive linearly.

Exposure

Now that we’ve seen what gamma is, it’s going to be much easier to explain what exposure is and how it behaves in Photoshop.

Exposure is a term in photography that is defined as the amount of light that reaches the camera sensor. It depends on different parameters such as shutter speed, iris aperture and sensor ISO. It is measured in EV (exposure value) and 1 EV more represents a doubled brightness. The converse being that 1 EV less gives 50% less brightness.

It turns out that in Photoshop, there is no camera. I know, it’s surprising.

So, how does exposure in Photoshop work?

Here, the exposure is not linear when corrected with Photoshop. That is, the bright values will be much brighter while the dark values will be a little less dark but the larger the brightness value, the greater the effect. And the higher the exposure value, the more the effect will be exaggerated.

Figure 14 — Different exposures with gamma correction = 0

With +1 in exposure in the adjustment layer, you get 1.37 times the base brightness. And for +2, 1.372 or 1.879 times the base luminosity and so on, +n gives 1.37n gives n times the base luminosity.

Why 1.37? Because Photoshop works on a gamma 2.2 and that 2 to the power of 1/2.2 is worth about 1.37 so our exposure doubles the brightness but it is the brightness if we were linear then Photoshop compensates for the gamma.

If we put the gamma correction at 1 over 2.2 or almost 0.45, when we add +1 in exposure, the brightness will double.

Our exposure does not double the brightness as in photography but will change the brightness in increments depending on the gamma.

Figure 15 — Correction with the Exposure adjustment layer

Offset

This third setting does what its name suggests, it shifts the brightness values of our image. How does it shift them? If we have a gamma correction of 0.45 then if we put a shift to 0.5, we add 50 out of 100 to the brightness or 0.5 out of 1 according to our scale. If we set it to 0.5, we remove brightness.

With the basic gamma of Photoshop, it will first shift the brightness of the pixel and then it will apply the gamma, so that the values are not shifted linearly but following the gamma applied to the image.

Figure 16 — Offsets on a scale of value that follows a gamma of 2.2

Curves

Once we have managed to get close enough with the Exposure adjustment layer, we will use the Curves adjustment layer.

This adjustment layer allows us to define more precisely and freely how the brightness changes in our image. Depending on the style of image we want, the curve will be different and here, we will try to get closer to the curve that UE5 uses with its tonemapper.

As we saw earlier, the horizontal axis represents all the brightness values of the layers below and the vertical axis indicates for each horizontal value what its new brightness will be.

Figure 17 — Correction with the Curves adjustment layer

We see that with this alone, we have largely achieved the goal of being below 5% brightness for the bottom row and that the other colors are already starting to get closer but some stand out much more than others.

Global hue and saturation settings

To correct this, we will go into a little more detail and modify some colors with the Hue/Saturation adjustment layer that will allow us to modify for color ranges the hue, saturation and brightness.

If we worked in RGB, it would be much more complicated to work with this adjustment layer and understand how it changes the color we have chosen. Moreover, no human can find it simpler to describe a color accurately in RGB than in HSL. (But our displays use RGB because each pixel contains a diode of each of these colors)

Figure 18 — Great analogy between RGB and HSL (Photo to the right by Sasikan Ulevik on Unsplash)

Histogram

Another very handy tool to use in some cases is histogram. They can be scary when you do not know them but they are very easy to use when you understand them.

Figure 19 — Histogram

The horizontal axis here represents brightness, to the far left are the darkest values and to the right the lightest. Here the values go from 0 to 255 because it is modeled on this damn RGB. We see that the lines of the dark values go very high, which means that there are many very dark pixels and we see that there are very few intermediate values on the histogram.

In our case, we want to have as many values as possible to the left since we work in difference mode and therefore the darker it is, the more similar the images are. Of course there will remain luminous values since we have the background of the image and the frame.

Currently, the biggest difference we have on the image is at the level of yellows so we will start by modifying the yellow of our image. By doing empirical tests by changing values, feel free to put extreme values to see what happens rather than trying to fall just if you do not know exactly where to go, you will learn much more.

Figure 20 — Correction of yellows

Brightness and saturation

You want to make a color brighter but the saturation goes down? This is normal, basically Photoshop is made for photography. When you make an object brighter by putting a light on it, it loses saturation. What for? An object has a color depending on the light it receives and the colors it absorbs. If we send too much of its color that it absorbs, it saturates and ends up returning some of this absorbed color. By reflecting this, the reflected light approaches a white light again. (If it receives a white light)

Figure 21 —Lit cube and one with a light 8 times more intense

You can even select different color ranges on the color spectrum at the bottom or use the eyedropper to select a particular color. We see that all the elements containing yellow have changed and that we are getting closer to our goal.

We just have to repeat the operation until we have corrected all the colors that have too big a difference to fall on a difference in brightness below 5% for all squares.

Figure 22 — Difference after color corrections

Create a LUT from an existing LUT

How do we transform these different adjustment layers into LUTs?

LUTs can be created with different formats, but Substance Painter uses a reference image modified by the LUT to tell the software how to interpret it.

Identity LUT

So there is an EXR file that we call linear (or identity) because it does not modify anything if we apply it. It’s the one we need to modify so that Substance applies the same modifications. It is available in Adobe Help on this page: https://helpx.adobe.com/substance-3d-painter/features/post-processing/color-profile.html

Oh no, in fact the link to download it is no longer valid and impossible to find it elsewhere! Too bad, we did it for nothing, thank you.

Well, there is a technique to solve this problem but it would be better to start on a sound basis, right? (In my case, I had seen that the LUT was no longer available before starting so I had applied my transformations on a gamma version.1.8 of Substance’s viewport)

We will take one of the LUTs provided in the Substance Painter software and we will take a very simple one, the one called Gamma 1.8 and we will recreate the linear file from it. We take the EXR and open it in Photoshop and since all it does is switch to Gamma 1.8, we will apply the reverse transformation to this EXR.

So we draw the exposure layer and we put gamma correction at

about 0.55. And we end up with our homemade linear LUT.

Figure 23 — Gamma 1.8
Figure 24 –Linear

And now, we apply all our settings that were put on the layer of Substance Painter to this EXR. All you have to do is import it as a colorlut in Substance and put it in Color Profile and you’re good to go!

Figure 25 — UE5

Unless Substance Painter decided to play a joke on you, which they did to me many times while I was doing my research and they decide not to apply the profile if you already had one and just restart the project to make it take it into account. A few hours wasted looking for why the EXR did not work to understand that it worked but just that there was a bug.

Figure 26 — Self-portrait after understanding the problem and going crazy (Rashomon by Akira Kurosawa)

Test different lighting

To verify that it was not a color profile that only worked in one case, I confronted several different lights between the engines and we generally remained very close even if the cyan tends to be exaggerated in Substance compared to UE5 in some cases even if it is very weak.

What if it hadn’t worked? We reapply the same principle with the new lighting to see the variations and we apply the transformations to the LUT and then we recompare.

Figure 27 — Comparison with a different HDRI
Figure 28 — Comparison with a different object

Congratulations to those who read it all

That’s it, you’ve made your homemade LUT and, I hope, learned new things through this long cobblestone.

You can congratulate yourself and do it to get other rendering styles than Unreal Engine 5.

I still give you the link to download it directly on my Gumroad and you can also download on another page of the same Gumroad the color chart.

The link : https://alexandrealvesdb.gumroad.com/l/ue5_lut

Links

https://chrisbrejon.com/

https://en.wikipedia.org/wiki/SRGB

https://docs.unrealengine.com/5.2/en-US/color-grading-and-the-filmic-tonemapper-in-unreal-engine/

https://www.cambridgeincolour.com/tutorials/gamma-correction.htm

https://learnopengl.com/img/advanced-lighting/gamma_correction_gamma_curves.png

--

--