This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Simple OpenGL texture glitches and Pixel Perfect questions.

Greetings,

I have a small issue with OpenGL texturing, which is not related to any GPU in particular. I've reproduced this problem with Radeon GPU and Mali GPU, so it's just a "I don't understand OpenGL" problem. However, I'm putting this in the ARM Mali graphics section, as it seems to be the most adequate section by elimination, and I'd like to know how this problem is called in OpenGL terms.

My problem is that when I use a texture atlas and apply a part of the texture atlas to a quad, it sometimes picks one more pixel from contiguous parts of the texture atlas.

The same quad displayed at different zones of the screen will glitch differently.

The problem tends to disappear when I use GL_NEAREST with GL_TEXTURE_???_FILTER, instead of GL_LINEAR. However, the texture become awfully pixelated then.

Buggy code

Here's an example of the code used :

psychic-octo-waffle/myy.c at master · Miouyouyou/psychic-octo-waffle · GitHub

The code basically generates two cards, divided in one opaque and two transparent parts, at two different parts of the screen (-0.02, 0 and 0.24, 0).

The non-converted atlas can be seen here. It's a set of 13x4 playings cards, 4 suits symbol, 4 turned cards and 4 backgrounds.

So, the normalised dimensions of each card part of the texture atlas are :

  • Width: 0.0625 (1/16)
  • Height: 0.25 (1/4)

I really doubt that these dimensions can generate rounding errors.

When executed, the code produces a window with two turned-around cards on the screen. Each one glitching slightly differently.

Here's the result :

two_cards.pngpixels.pngQuestions

So my questions are :

  • What triggers this problem exactly ?
  • What are the best way to achieve a nice Pixel Perfect texturing with OpenGL ?
  • Is this problem mentioned in the OpenGL ES 2.x specification ?
Parents
  • What triggers this problem exactly ?

    Before anything else, it's worth checking your coordinates match what OpenGL ES expects. GL pixel and texel centers are at half-points, not integer coordinates.

    E.g.

    • the pixel coordinate of the bottom-left pixel in a 1920x1080 screen is not (0.0, 0.0) it's at (0.5, 0.5).
    • the M'th unfiltered texel center in a texture of side length N is not at coordinate (M / N), it's at ((0.5 + M) / N)

    If you try to use integer sample locations you'll end up half a pixel/texel off where you originally intended (which may be what is causing your problem, as filtering will pull from the neighboring pixels).

    With linear filtering at any sample point less than ((0.5 + M) / N) will result in at least some contribution from the previous texel, and any sampling at a point higher than this will result in at least some contribution from the next texel. If your cards are freely animated then your sample points will move around inside that texel box, so it's almost impossible to prevent contribution from the texels either side.

    What are the best way to achieve a nice Pixel Perfect texturing with OpenGL ?

    It's not always easy, or even possible, especially when things are moving around the screen; there is an implicit disconnect between pixel centers (sampling points) and the geometry (and hence texture coordinates). On most "line art" renderers and browsers pixel-perfect is achieved by cheating (snapping vertices to an exact pixel center). It's possible to do this in the vertex shader, but it isn't common in 3D rendering because it's not needed (and not useful except for exactly vertical and horizontal lines), and so most applications just learn to live with it instead ...

    The easy fix is to leave a small transparent gap of a couple of pixels between sprites in the atlas which gives you some fault tolerance.

    Is this problem mentioned in the OpenGL ES 2.x specification ?

    The coordinate system is definitely mentioned, but the implications of it are left as an exercise to the reader ...

    Also you mentioned "converted" with respect to the texture itself - what texture format are you using? If you are using any compression, note that most compression schemes for GPUs are block-based and can definitely cause bleeding colors across texels inside the block, which may not neatly align with your card edges. This is another good reason to leave some blank space around each card where space > block size of the compression scheme.

    Hope that helps,
    Pete

Reply
  • What triggers this problem exactly ?

    Before anything else, it's worth checking your coordinates match what OpenGL ES expects. GL pixel and texel centers are at half-points, not integer coordinates.

    E.g.

    • the pixel coordinate of the bottom-left pixel in a 1920x1080 screen is not (0.0, 0.0) it's at (0.5, 0.5).
    • the M'th unfiltered texel center in a texture of side length N is not at coordinate (M / N), it's at ((0.5 + M) / N)

    If you try to use integer sample locations you'll end up half a pixel/texel off where you originally intended (which may be what is causing your problem, as filtering will pull from the neighboring pixels).

    With linear filtering at any sample point less than ((0.5 + M) / N) will result in at least some contribution from the previous texel, and any sampling at a point higher than this will result in at least some contribution from the next texel. If your cards are freely animated then your sample points will move around inside that texel box, so it's almost impossible to prevent contribution from the texels either side.

    What are the best way to achieve a nice Pixel Perfect texturing with OpenGL ?

    It's not always easy, or even possible, especially when things are moving around the screen; there is an implicit disconnect between pixel centers (sampling points) and the geometry (and hence texture coordinates). On most "line art" renderers and browsers pixel-perfect is achieved by cheating (snapping vertices to an exact pixel center). It's possible to do this in the vertex shader, but it isn't common in 3D rendering because it's not needed (and not useful except for exactly vertical and horizontal lines), and so most applications just learn to live with it instead ...

    The easy fix is to leave a small transparent gap of a couple of pixels between sprites in the atlas which gives you some fault tolerance.

    Is this problem mentioned in the OpenGL ES 2.x specification ?

    The coordinate system is definitely mentioned, but the implications of it are left as an exercise to the reader ...

    Also you mentioned "converted" with respect to the texture itself - what texture format are you using? If you are using any compression, note that most compression schemes for GPUs are block-based and can definitely cause bleeding colors across texels inside the block, which may not neatly align with your card edges. This is another good reason to leave some blank space around each card where space > block size of the compression scheme.

    Hope that helps,
    Pete

Children