2
\$\begingroup\$

I'm drawing an 2D array of cubes in 3D space using OpenGLES. The texture that I have bound is spritesheet-style; that is, it's multiple textures packed into one. If you look closely at the front of the image below, you can see 1-pixel thick lines that are lighter than the crates. And, thicker lines in the back of the image. They are not supposed to be there, and are what I believe to be pixels from another texture in the spritesheet.

I'm using GL_NEAREST_MIPMAP_NEAREST and GL_NEAREST for the min and mag filters, and I've tried all of the different clamping modes and nothing changes (GL_CLAMP_TO_EDGE, GL_REPEAT, GL_MIRROR_REPEAT).

At first I thought it was float precision error, but now I think it's something else (since using precision highp float in the shader makes no difference).

Screenshot showing texture wrapping artifacts

\$\endgroup\$
  • \$\begingroup\$ Thaty's how mipmap filtering works - every next level texture is x2(x4) smaller and it get progressively smaller and more of a "all colors blended" \$\endgroup\$ – Kromster says support Monica Jul 31 at 9:23
  • \$\begingroup\$ @Kromster he is talking about the lines between the tiles. \$\endgroup\$ – Bálint Jul 31 at 14:19
  • \$\begingroup\$ stackoverflow.com/questions/19611745/… \$\endgroup\$ – Bálint Jul 31 at 14:51
  • \$\begingroup\$ @Bálint right, thats what I meant. Since TS is sampling from an atlas, he gets neighbour tiles "bleed in". \$\endgroup\$ – Kromster says support Monica Aug 1 at 4:52
  • \$\begingroup\$ @Kromster ah, okay, sorry \$\endgroup\$ – Bálint Aug 1 at 12:26
1
\$\begingroup\$

I figured out what was going on. The problem was not floating point precision, and not that I needed to make my own mipmaps to blend each level correctly. There were actually 2 problems:

  1. I was using the Max Rects packer algorithm with non-power-of-2 sized images to create the texture atlas.
  2. I wasn't setting GL_TEXTURE_MAX_LEVEL

What I was doing:

  • Use Max Rects on non-power-of-two packing to create a texture atlas. Textures are aligned at pixel boundaries.
  • glGenerateMipmap(GL_TEXTURE_2D); making blending the texture atlas textures into each other even on level 1

What I'm doing now:

  • All textures are power of 2. 128x128 is the smallest sized texture in a 4096x4096 texture atlas.
  • glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 7); - This is new. Don't allow anything below mipmap level 7, because 4096 / (2^7=128) = 32. This makes the code stop generating mipmaps once the smallest texture in the atlas becomes 1 pixel by 1 pixel.
  • glGenerateMipmap(GL_TEXTURE_2D); - Now scales down the atlas correctly because all the textures are aligned to 1/32 of the width or height of the atlas rather than 1/width or 1/height.

And now the min filter can use 2 modes without texture bleeding:

  • GL_NEAREST_MIPMAP_NEAREST
  • GL_NEAREST_MIPMAP_LINEAR

The following 2 min filter modes still have bleeding issues, but I'm not planning on using them anyway:

  • GL_LINEAR_MIPMAP_NEAREST
  • GL_LINEAR_MIPMAP_LINEAR

The reason is because they are interpolating the mipmaps to sizes that are not powers of two, which makes the textures in the texture atlas aligned to points in between pixels, causing the bleeding. The only way I think this can be solved is by adding a border around each texture in the texture atlas. The only problem with that is that the border would have to be 128 or 64 pixels, the size of the smallest texture or half the size of the smallest texture (if you use half pixel offset). And that's a huge waste of video RAM.

So I went with GL_NEAREST_MIPMAP_LINEAR:

enter image description here

\$\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.