For an OpenGL 3.1 app, I’ve texture atlas’d all of my decorative sprites which sit on my terrain, into one sprite sheet, as there are lots of them and I’d prefer to avoid lots of texture binds. Also, I’m going for an intentional retro look which means GL_NEAREST
is fine for me. All looks good when moving the camera/player around – mostly, that is. When the camera is at certain positions/angles, textures on sprites may bleed into the neighboring sprite, even on GL_NEAREST
. These errors pop in and out, and aren’t always there. For example, if I stop the camera at such a position that a bleeding error appears on the tree sprite in front of me, and if I then move my mouse 1 pixel in any direction, that artifact may vanish again.
I’m not convinced that inserting padding pixels around every single sprite is the best solution because then I’d kind of be destroying one of the points of a texture atlas - to have efficiently and tightly packed textures. Putting 1-2px border around every sprite would seem to be wasted space, would reduce the available graphical detail of every sprite, (12-14px instead of 16px wide), and (I think) theoretically it may not solve the problem anyway if I move too far away into the distance.
“Fudging” the UVs to render in the frag shader also seems wrong to me. i.e. Rendering 0.0 + 0.0001 to 0.125 - 0.0001 rather than 0.0 to 0.125, as we will then be squashing/deforming the shapes of the pixels at the edge of every sprite.
How should I otherwise solve this problem, if even possible, without going the “different texture for every single sprite and use CLAMP” route?
My textures are set up like this:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterI(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameterI(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterI(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
And in the fragment shader, I retrieve the UVs like:
in vec2 fUVs;
uniform sampler2D uTex0;
...
vec4 tex_color = texture(uTex0, fUVs);
And when creating those UVs on the CPU, I’m doing basic float math such that the UVs values (should?) always be able to be represented accurately by floating points, since all sprites are either powers of 2, or at least, multiples of 16.
Also, I’m not (I don’t think) using mipmaps. Should I be? Or would that make bleeding even more likely, in this case?