Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a 1D lut in C++ for GLSL

I'm beginning to understand how to implement a fragment shader to do a 1D LUT but I am struggling to find any good resources that tell you how to make the 1D LUT in C++ and then texture it.

So for a simple example given the following 1D lut below:

enter image description here

Would I make an array with the following data?

int colorLUT[255] = {255,
                     254,
                     253,
                     ...,
                     ...,
                     ...,
                     3,
                     2,
                     1,
                     0};

or unsigned char I guess since I'm going to be texturing it.

If this is how to create the LUT, then how would I convert it to a texture? Should I use glTexImage1D? Or is there a better method to do this? I'm really at a lose here, any advice would be helpful

I'm sorry to be so brief but I haven't seen any tutorials about how to actually make and link the LUT, every tutorial on GLSL only tells you about the shaders they always neglect the linking part.

My end goal is I would like to know how to take different 1D LUTs as seen below and apply them all to images.

enter image description here

like image 566
Maggick Avatar asked Sep 30 '22 14:09

Maggick


1 Answers

Yes, you can use 1D textures as lookup tables.

You can load the data into a 1D texture with glTexImage1D(). Using GL_R8 as the internal texture format, and specifying the data as GL_UNSIGNED_BYTE when passing it to glTexImage1D(), is your best choice if 8 bits of precision are enough for the value. Your call will look like this, with lutData being a pointer/array to GLubyte data, and lutSize the size of your LUT:

glTexImage1D(GL_TEXTURE_1D, 0, GL_R8, lutSize, 0, GL_RED, GL_UNSIGNED_BYTE, lutData);

If you need higher precision than 8 bits, you can use formats like GL_R16 or GL_R32F.

Make sure that you also set the texture parameters correctly, e.g. for linear sampling between values in the lookup table:

glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

You then bind the texture to a sampler1D uniform in your shader, and use the regular texture sampling functions to retrieve the new value. Remember that texture coordinates are in the range 0.0 to 1.0, so you need to map the range of your original values to [0.0, 1.0] before you pass it into the texture sampling function. The new value you receive from the texture sampling function will also be in the range [0.0, 1.0].

Note that as long as your lookup is a relatively simple function, it might be more efficient to calculate the function in the shader. But if the LUT can contain completely arbitrary mappings, using a 1D texture is a good way to go.

In OpenGL variations that do not have 1D textures, like OpenGL ES, you can use a 2D texture with height set to 1 instead.

If you need lookup tables that are larger than the maximum supported texture size, you can also look into buffer textures, as suggested by Andon in his comment.

like image 194
Reto Koradi Avatar answered Oct 23 '22 21:10

Reto Koradi