I’m currently fighting vertex stitching” in my game. Here’s what that looks like with just scaling, look for the flickering black lines between tiles.

This happens when either scaling or translating the camera (inversely, the grid of tiles) by fractional values.

Two solutions” recommended around the web that I’ve already implemented:

  • Pre-multiplied alpha
  • GL_NEAREST min and mag filtering

I believe the cause of the issue is floating-point imprecision.


OpenGL (and all other hardware rasterizers) only guarantees gapless rendering of the edge between two triangles if the edges exactly match. And that means you can’t just have one triangle next to the edge of another. The two triangles must have identical vertices on the shared edge between them.

The other thing you have to do is make certain that the two shared vertices between the two triangles are binary identical. The gl_Position output from the vertex shader needs to be the exact same value.

So where does the imprecision in my code creep in? I believe it’s this:

in vec2 aPosition; // either -0.5 or 0.5
in mat3 iTransform; // vertex transform, only translation in the video
uniform mat3 uView; // camera transform, only scaling in the video
vec3 pos = uView * iTransform * vec3(aPosition, 1.0);
gl_Position = vec4(pos.xy, 0.0, 1.0);

Ok so how can I fill in the gaps and still support fractional scaling?

The tiles in my game are stored in a texture atlas. If tiles rendered next to each other don’t share binary identical” vertices, OpenGL is forced to sample outside of the tile’s UV coordinates within the atlas, reaching into the transparent space.

Let’s see what happens when the empty space in the tile atlas is filled with red.

Before After

Great! So the gaps CAN be filled. I think the solution here is to bleed the textures.

Before After

Completely fixed! …right?

Unfortunately, no. Walking far enough around the world reveals some additional, very infrequent stitching.

Because the lines are black and not red, I’m not sure that this is just fractional differences between vertices. I think the distance between some vertices is sometimes greater than 1, causing real gaps.

I know that if I clamp the camera offset to integer values, the gaps disappear. This introduces two problems: the map now has a minor snapping effect, and the player is now always fractionally offset from the map, causing the player to jitter. I can solve the player jitter by also rounding the player position.

I think for now I’m just going to accept the black line flickering. The background is dark enough that the lines will probably never be noticed.

December 10, 2022