A color look-up-table or LUT is used for color-grading your game. LUTs are often used because it eliminates the need to code multiple effects like contrast, curves, saturation etc. Instead a LUT lets you use programs like Photoshop or similar and all effects that comes with that program to color-grade your game. You can then export the LUT and use it in your engine.
A color look-up-table stores a color graded color for every possible color. So if you want your game to look less saturated you store less saturated colors in the table.
Look-up-tables are usually a 2D texture in game-engines and look something like the image below:
Look-up-tables always contain 3 dimensions of information for Red, Green and Blue. In a 2D LUT this is stored by having multiple images in one, as in the image above. The X value in each cube represents the Greens, the Y value represents the Reds and each cube has a different Blue.
Since the LUT has 3 dimensions it is logical store it as a 3D texture. Luckily OpenGL and DirectX supports 3D textures, which acts as a cube of colors instead of a flat plane.
Having a 3D texture is good to use because it gives use 3D linear sampling for free. Linear interpolation between pixels is necessary because the LUT doesn't contain all 256^3 colors and more like 25^3 colors. Without linear interpolation there would be a significant loss of colors.
Since images are 2D we can't create a 3D texture from an image. Therefore we use a .CUBE file. These can be exported from the newer versions of photoshop and can easily be loaded in to create a 3D texture in your engine.
There are multiple file formats that store LUTs but we will use .CUBE since it has a formatting that is easy to read.
.CUBE files contain two important keywords:
#LUT size: the next line contains the LUT size.
The size is defined when exporting the LUT from photoshop, and tells you the dimensions of the 3D texture. A larger number will also result in higher color precision.
#LUT data points: all new lines from now on will contain color data.
The data is stored in the CUBE file starting from color: R:0.0 G:0.0 B:0.0 and ends at color R:1.0 G:1.0 B:1.0. In this case when the size is 25, the first 25 colors represents the bottom X axis in the cube, we then increment the Y axis for every 25 colors, and increment the Z axis every 25^2 colors and so on.
below you can see an example of how a .CUBE file usually starts.
Since images are 2D we can't create a 3D texture from an image. Therefore we use a .CUBE file. These can be exported from the newer versions of photoshop and can easily be loaded in to create a 3D texture in your engine.
There are multiple file formats that store LUTs but we will use .CUBE since it has a formatting that is easy to read.
After loading all data we need to create a 3D texture to sample from in the fragment shader. This is done differently depending on what graphics API you use. In this example we use OpenGL.
To use the 3D texture we want to sample it in the fragment shader, preferably in an after shader so all pixels on screen gets effected and to minimize sampling from the LUT.
In the fragment shader we need a uniform sampler of the current frame and the LUT.
The uniforms needs to be given an ID when initializing the shader and both of these need to be bound to the shader before using it.
Sampling the LUT in the shader is easy since the original color can be used as the coordinates/uvw for the LUT. All we need to do is sample the incoming color, then sample the LUT using that color as coordinates. This will then be the resulting color.
The resulting image is now color-graded using the LUT and can be drawn to screen.
You now have a really easy way of making your engine look great! Being able to color-grade in photoshop is super convenient and will speed up your workflow.
Copyright © All Rights Reserved