locked
linear texture sampler is sampling outside the texture coordinates

    Question

  • Hi, I'm using linear texture sampling in a spritebatch. Our 2D game allows zooming in and out, and when zoomed out and looking at a sprite, I sometimes see pixels along the edges of the sprite that belong to an adjacent sprite in the texture sheet. When I use point sampling this problem goes away, except of course the sprites look very pixelated.

    My understanding is that the linear sampler is sampling pixels from outside the rectangles specified by the texture coordinates. Is there a way I can get around this but still use linear sampling? Would shifting the texture coordinates inward by a small offset work, for example?




    • Edited by davidb353 Monday, May 12, 2014 3:41 PM
    Monday, May 12, 2014 3:38 PM

Answers

  • Your texture sheet or texture atlas (as I call them) is going to require some intelligence to sample correctly.

    Basically if you linearly sample a point, it's going to use a weighted average of the 4 pixels adjacent to those coordinates.  (If you use bilinear sampling then you're going to use 8 samples: 4 from the mip level above and 4 from the mip level below.)  If you don't want that, then you can adjust your UV coordinates (texture sample location) to a different spot with clamping.  The sampler doesn't know about the "rectangles specified by the texture coordinates".  It just knows u,v.   [* technically it knows a bunch of stuff from the rasterizer like x,y,z,rhw and derivatives, but it doesn't care that your texture mesh corresponds to a rectangle.  In fact, it's all designed so that polygons that share an edge will sample pixels in such a way that you can't see rasterization seam of that edge.  When you think about it, this is very important for drawing rectangles at all because a rectangle is just two triangles.]

    Hopefully the discrete textures within the sheet are rectangular.  You can simply clamp your uv texture coordinates to the bounds of the sub-image rectangle within the texture.  Each polygon will likely have its own sub-image index, and therefore have its own clamping rectangle (prepare to provide some instancing data to achieve this!).  You can also write the shader to assign a "border" to your images so that you define what is supposed to be there, if not the adjacent pixel in the texture.  Perhaps you want to clamp the texture image, or perhaps you want black or transparent to be linearly blended in.  If your sub-images fall on regular boundaries (like if you have many 32x32 textures within one 256x256 texture or something like that) then you can possibly just perform the clamping arithmetically in the pixel shader by computing which box your texture sample falls in and then clamping it accordingly without assigning it a clamping rectangle -- basically you can infer the clamping rectangle from the coordinates.  (This is a little more error prone due to rounding in the rasterizer, but you might be able to hide the index data in a third texture coordinate if you need to fix it.)

    One final warning that mipmapping (bilinear sampling) defeats the texture sampling boundaries entirely.  This is because heavily reduced levels of the mipmap will have pixels that sample across the boundaries of your individual sub-image rectangles within your texture sheet.  There's not really a nice way around that other than to do the sampling yourself.

    My advice is not to just rely on default sampling functionality, but instead to think carefully and define the desired correct sampling yourself, and then write a shader program to achieve it.

    Alternative:

    If this intimidates you:  place your textures within your texture sheet differently.  Make use of some margins / borders to mitigate the problem.

    • Marked as answer by davidb353 Monday, May 12, 2014 8:40 PM
    Monday, May 12, 2014 7:55 PM

All replies

  • This behavior is controlled by the AddressU, AddressV, AddressW members of the sampler state.

    http://msdn.microsoft.com/en-us/library/windows/desktop/ff476207(v=vs.85).aspx

    See the D3D11_TEXTURE_ADDRESS_MODE enumeration

    http://msdn.microsoft.com/en-us/library/windows/desktop/ff476256(v=vs.85).aspx

    Monday, May 12, 2014 6:33 PM
  • Your texture sheet or texture atlas (as I call them) is going to require some intelligence to sample correctly.

    Basically if you linearly sample a point, it's going to use a weighted average of the 4 pixels adjacent to those coordinates.  (If you use bilinear sampling then you're going to use 8 samples: 4 from the mip level above and 4 from the mip level below.)  If you don't want that, then you can adjust your UV coordinates (texture sample location) to a different spot with clamping.  The sampler doesn't know about the "rectangles specified by the texture coordinates".  It just knows u,v.   [* technically it knows a bunch of stuff from the rasterizer like x,y,z,rhw and derivatives, but it doesn't care that your texture mesh corresponds to a rectangle.  In fact, it's all designed so that polygons that share an edge will sample pixels in such a way that you can't see rasterization seam of that edge.  When you think about it, this is very important for drawing rectangles at all because a rectangle is just two triangles.]

    Hopefully the discrete textures within the sheet are rectangular.  You can simply clamp your uv texture coordinates to the bounds of the sub-image rectangle within the texture.  Each polygon will likely have its own sub-image index, and therefore have its own clamping rectangle (prepare to provide some instancing data to achieve this!).  You can also write the shader to assign a "border" to your images so that you define what is supposed to be there, if not the adjacent pixel in the texture.  Perhaps you want to clamp the texture image, or perhaps you want black or transparent to be linearly blended in.  If your sub-images fall on regular boundaries (like if you have many 32x32 textures within one 256x256 texture or something like that) then you can possibly just perform the clamping arithmetically in the pixel shader by computing which box your texture sample falls in and then clamping it accordingly without assigning it a clamping rectangle -- basically you can infer the clamping rectangle from the coordinates.  (This is a little more error prone due to rounding in the rasterizer, but you might be able to hide the index data in a third texture coordinate if you need to fix it.)

    One final warning that mipmapping (bilinear sampling) defeats the texture sampling boundaries entirely.  This is because heavily reduced levels of the mipmap will have pixels that sample across the boundaries of your individual sub-image rectangles within your texture sheet.  There's not really a nice way around that other than to do the sampling yourself.

    My advice is not to just rely on default sampling functionality, but instead to think carefully and define the desired correct sampling yourself, and then write a shader program to achieve it.

    Alternative:

    If this intimidates you:  place your textures within your texture sheet differently.  Make use of some margins / borders to mitigate the problem.

    • Marked as answer by davidb353 Monday, May 12, 2014 8:40 PM
    Monday, May 12, 2014 7:55 PM
  • Great reply. Thank you!
    Monday, May 12, 2014 8:41 PM