Tiling issue using a texture atlas with half pixel correction and no mipmaps

As the title states, I’m building a texture atlas from some simple PoT textures using:

  • half pixel correction for the UVs
  • mipmaps disabled
  • 0p padding, 4p padding, 64p padding… makes no difference

yet I’m getting some ugly results if I enable bilinear filtering:
In the center of the image 4 texture instances touch and u can see the seams, but the texture itself is seamless.
alt text
Looks like if 1 pixel in each side is missing.

alt text
Link to bigger image

  • Left: Screenshot from unity using Point filter (ignore the brown sides, those are just decals)
  • Center: 4 instances of the texture put side by side and scaled on Gimp
  • Right: Screenshot from unity using Bilinear filter

Any idea of how to fix this? Disabling filtering (setting it to Point) works but I’d like to keep it at bi-trilinear as it looks a lot better, plus I don’t really understand why is this happening.

Thx in advance.

Edit: Added exact code for half pixel correction

 xOffset = this.Atlas.texelSize.x / 2f;
 yOffset = this.Atlas.texelSize.y / 2f;
			
 public Rect GetHalfPixelCorrectedMapping(int textureId) {
            Rect uvBounds = this.Mappings[textureId];
            uvBounds.xMin += this.xOffset;
            uvBounds.xMax -= this.xOffset;
            uvBounds.yMin += this.yOffset;
            uvBounds.yMax -= this.yOffset;

            return uvBounds;
        }
		
		
foreach (Vector2 uv in mesh.uv) {
                float x = Mathf.Lerp(uvBounds.xMin, uvBounds.xMax, uv.x);
                float y = Mathf.Lerp(uvBounds.yMin, uvBounds.yMax, uv.y);
					.........
                    .........
                }

Applying the half-pixel offset to “center” each pixel eliminates the seams you’d see in this case, but are you properly accommodating the other edge(s)?

For example, if you’re reading a normal texture, you’d read from the start of pixel (0, 0) and read to the end of, say, (15, 15). That said, in a 16x16 texture, if the first pixel is considered to be located at 0-1 texture coordinate (0.03125, 0.03125), then the final pixel would be located at (0.96875, 0.96875).

If your texture coordinates to read in the image were based around a 0-1 range (conceptually), then adding a half-pixel to 1 would enter the bounds of the neighboring texture in the atlas.