Repeating textures when using a texture atlas

When textures are all in their own Texture2Ds, drawing them repeating is simple. You just set the SamplerState to wrap and draw using a source rectangle bigger than the Texture2D’s bounds.

That way, unfortunately, doesn’t work when using a texture atlas, where multiple textures are stored in a single Texture2D. Making the source rectangle bigger would end up drawing other textures.

I’m hoping to find another way to draw repeating textures (using SpriteBatch) besides

  • not using a texture atlas, instead having each texture in its own Texture2D
  • manually repeating the texture by calling Draw repeatedly

Is there another solution, or are those the only two options?

You could do it passing a shader to spritebatch but im not sure how expensive it would be.
It’s definately not to easy to explain either and so im just going to sort of pesudo spit it out.

Basically you need to modulate against the u v positional area on the image conditionally.

You would need to pass in the source rectangle to modulate the uv against it.
It would be best to pass it in with virtual coordinate form.
sourceRectangle / image.Bounds
the image bounds is a rectangle the size of the image like 0,0,100,100
the source is maybe like 10,10,20,20

Now your uv is passed in as texture coords you would want to read them and basically modulate those coordinates by the min max of the virtual source rectangles coordinates.

To say
your textcoords.x - virtualRect.x is less then 0 you need to modulate the difference from virtualRect.Width in this case that would be virtualRect.z the fractional amount you get back is subtracted from virtualRect.Width to give a new u coordinate.
your textcoord.x - (virtualRect.Width + virtualRectangle.x) = su , is more then 0 then
take that and divide it by the virtual width and add the fractional amount to virtualRect.x
frac(textcoord.x / (virtualRect.Width)) + virtualRect.x = new u coordinate

Repeat those steps for V using the virtual y and height.
When you have the new U,V you grab the pixel out of the image with it.

When you pass in the virtual rectangle you pass a float4 so width height is going to be z w

You could do this vertex shader side modulating based on actual pixel position and gain tons of control over it but that is even more complicated to explain and requires a couple more values to be passed to the shader.

Thanks for the response. I realized after I posted that it could probably be done with shaders. I guess I’ll have to brush up on my HLSL, which I am very inexperienced in.

Well i just replied to this and its pretty similar for a starting basis.

It’s 2018: use TextureArrays and a coordinate scheme such as UDIM.

If you really want to use an atlas instead of arrays than you also have to handle mipmapping yourself (dfDx/dfDy | ddx/ddy).

If you don’t want to fuss with mipping then you need to pad the textures considerably so that mip-blead doesn’t occur as a result of mip-generation.

Either way texel fetches are going to be much more expensive than normal. TextureArrays are so much cheaper.