I need a lookup table in a shader. The input values would be color values and the output other color values. Something like:

uniform float lut[256];

color = vec3(lut[int(color.r*255.)], lut[int(color.g*255.)], lut[int(color.b*255)]);

does what I need but certain implementations of OpenGL ES do not allow arrays with variable indexing so finally I've arrived to the conclusion that the most portable way is to have a 2D texture as the LUT. A texture of 256x256 could store many different lookup tables, each one (256 entries) in a single row.

In order to load a row in the texture (c++) I would use:

glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 1, GL_LUMINANCE, GL_UNSIGNED_BYTE, data);

to store a table in the first row (I assume that internally in the texture I'd have the value repeated in R, G and B)

To fetch the LUT in the fragment shader I'd use texture2D(lut,vec2(index, constRow)) (index in the range 0-1 and constRow = 0 being the row in the texture where it is stored the lut).

Is that a reasonable way to implement that?

Update: In order to fetch values in the texture-LUT you need normalized indexes (0.0-1.0), so to access row 7 I have to index it as texture2D(lut, vec2(index, 7./255.)); From what I see the result is (or may be) an interpolation with the two other consecutive rows.

  • \$\begingroup\$ Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. \$\endgroup\$
    – Kromster
    Sep 1, 2014 at 17:04
  • \$\begingroup\$ Sorry for the fuzzy question. I've edited it, hopefully it's clear now. \$\endgroup\$
    – Joan
    Sep 1, 2014 at 18:14
  • \$\begingroup\$ If everything works, then what is the problem that you are facing? GDSE is not a "review my solution" kind of place. It's more like a QA ;) \$\endgroup\$
    – Kromster
    Sep 2, 2014 at 5:39
  • \$\begingroup\$ I was asking for the case someone addressed the same problem with a different aproach (I though the problem posed was quite frequent). So far my solution is not as simple to implement as one would say at first sight, at least for me. \$\endgroup\$
    – Joan
    Sep 2, 2014 at 10:10
  • 1
    \$\begingroup\$ Have you tried setting the texture sampling to GL_NEAREST for the texture? You just want to explicitly disable the bilinear filtering \$\endgroup\$
    – Steven Lu
    Sep 2, 2014 at 15:00

1 Answer 1


Your normalization is not exactly correct. You need to note that the OpenGL standard says

A fragment is located by its lower left corner, which lies on integer grid coordinates. Rasterization operations also refer to a fragment’s center, which is offset by (1/2,1/2) from its lower left corner (and so lies on half-integer coordinates).

Therefore, the integer pixel coordinate (i,j) is located at the normalized coordinate ((i+0.5)/W, (j+0.5)/W).


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .