2
\$\begingroup\$

I want to look up a texel from my GLES2 GLSL fragment shader using un-normalized texture coordinates (0-w, 0-h instead of 0-1, 0-1). The reason is that this texture is used as a look up table and I get precision problems with normalized coordinates.

I see that GL_TEXTURE_RECTANGLE is not supported wihtout extensions and neither is texelFetch(), so I have ruled out those options.

Thanks!

\$\endgroup\$
  • \$\begingroup\$ If you are getting precision problems it's possible that you've set GL_LINEAR instead of GL_NEAREST. \$\endgroup\$ – badweasel Jan 2 '15 at 19:55
  • \$\begingroup\$ Are you absolutely sure that you are actually running into precision problems and not making a far simpler mistake such as not sampling at texel centers? If you have simply divided your texture coordinates by the dimensions of your texture, you are actually going to be sampling on texel boundaries rather than center. Even with nearest-neighbor filtering, you want to sample as far away from texel boundaries as possible to avoid looking up the wrong value (especially if you have limited precision working against you). \$\endgroup\$ – Andon M. Coleman Jan 3 '15 at 2:13
  • \$\begingroup\$ To be honest I have asked this on behalf of a friend to show that this site has merit. In his face, I bet he did that mistake! \$\endgroup\$ – Lennart Rolland Jan 3 '15 at 5:38
1
\$\begingroup\$

I'm not sure what you mean by un-normalized texture coordinates. All texture lookups are going to be in the range of 0-1. You can have them be anywhere in that range however. If you're having precision problems in the range of 0-1 I suspect something else going on.

A couple of hints to help fix this:

For example, make sure you don't have GL_LINEAR set for your texture. For a lookup to be accurate you're probably going to want GL_NEAREST. Otherwise it could average the data around the textel and give you a interpolated result. Same goes for the GL_WRAP settings. You probably want something like this:

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

I once had a large texture atlas (2048x2048) with a bunch of sprites on it. And in one small area of the texture I had a look up table. So in that case the lookup S started at 1024/2048 and ended at 1536/2048. So I passed to the shader uniforms for SStart and SWidth. And TStart and TWidth. SStart was 0.5 and SWidth was 0.25. In my S direction I had 512 steps on the lookup, or 0.25 of 2048. In the T direction it was also a small segment, but there I also needed to make sure it didn't bleed over in to the one next to it. So I made each lookup in the texture about 8 pixels wide, and in code I aimed to hit the middle.

The math for the S direction was an input of 0-1, so the formula was s = SStart + input * SWidth.

There is plenty of precision in a lowp variable to handle a lookup in the range of 0-1 for any texture size that your hardware supports. Even 1/4096. This is what the gxf card is designed to do.

\$\endgroup\$
  • 2
    \$\begingroup\$ Unnormalized texture coordinates as in texel addressing. In desktop GL there were rectangle textures in legacy versions that used integer texture coordinates instead of normalized coordinates (but their primary appeal was usually that they supported non-power-of-two dimensions pre-GL 2.0); later they introduced an explicit texture lookup function for that purpose (texelFetch). \$\endgroup\$ – Andon M. Coleman Jan 3 '15 at 1:59
  • \$\begingroup\$ @AndonM.Coleman We looked into that legacy feature and spent some time figuring out if it was part of GLES2, but unfortunately (fortunately?) it wasn't \$\endgroup\$ – Lennart Rolland Jan 3 '15 at 5:40
  • \$\begingroup\$ I still don't understand why you wouldn't just convert the lookup to the range of 0-1. And then check the things I mention above to fix the precision issues. Even if you could send a legacy non-normalized value it would still internally convert it to a % range of possible values. \$\endgroup\$ – badweasel Jan 4 '15 at 2:05
0
\$\begingroup\$

What you want is a texture rectangle. Take a look at this question.

Usually you can get around this by converting to normalized values so that they map to the pixel coordinates centers of the stored image which is specified in the OpenGL standard as:

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).

So if you want to retrieve the pixel at (i,j) where i=0,1,2,..,W-1 and j=0,1,..,H-1 then use the normalized coordinate (u,v) = ((i+0.5)/W, (j+0.5)/W) and make sure filtering is set to GL_NEAREST.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.