[GLSL] Making a Texture Atlas repeat.

I want to produce the same effect GL_REPEAT does, but with a texture atlas. This means the texture is not one big texture in opengl, but only a part of a big texture sheet.

I want to accomplish this with GLSL, since I already use it and think it’s the only way.
I’ve tried this but this only scales the texture, and I’m not sure what “offset” is…

I would have following inputs in my fragment shader:
the uniform texture,
the varying texture coord as a vec2,
and an attribute vec2 “repeat”, which is for example 4, if the user wants to tile the texture 4 times over the surface.

Why that way, why not
[x] Simply use one texture
Answer: I’d need to put lots of floor textures into seperate textures, and I’d need to call glBindTexture a lot, which would kill the performance…
[x] Simply use more quads:
This kills performance too, since a repeating texture would have exactly the same effect and would need much less vertex power.

Anyways: If there is another way than GLSL and usual texture sheets, please educate me… I’ve thought about texture arrays, is that possible?

Tip: the fract() function. It takes in a floating point number and returns (x - floor(x)), which is a the decimal value between 0 and 1. The rest depends on how your texture atlas looks.

by decimal we mean floating point

Yes… but I still couldn’t figure it out :confused:

I still have to fiddle around with the input I give to my shaders, since only giving a [ïcode]vec2 repeat[/icode] is not enough…

Something like this (kind of psuedo code)


//You can make these attributes too to avoid having to change them between draw calls.
uniform vec2 atlasCoord; //Top left corner of the atlas image
uniform vec2 atlasSize; //Size of the atlas image

attribute vec2 localTexCoords; //From 0 to 1, repeats outside that range

void main(){
    vec4 textureSample = texture2D(sampler, atlasCoord + fract(localTexCoords)*atlasSize);
    ...
}


IMO its easier just to render multiple sprites. No need for extra floats per vertex or uniforms (which in most instances will just be unused anyways).

Keep in mind most games use variation, so instead of repeating the same grass tile, you end up scattering the ground with multiple grass variants.

Pushing more verts is really no big deal for OpenGL – its designed for complex 3D scenes after all, and we’re pushing a relatively small number of verts even with the whole screen filled with tiles.

One thing to remember when writing you’re own samplers is you gotta account for everything…in this case if you’re no point-sampling the texture, then you need to remember to have a ‘border’ around the base texture so the proper samples are read.
(BTW: Isn’t the call just ‘texture’ these days?)

Ah yeah… I guess I’ll just drop it, since GL_LINEAR does not work properly :slight_smile:
I think I’ll educate myself some texture arrays…

But you can see its repeating 4 times, and I fully understand what you did there now, theagentd :slight_smile: thank you…

Your point being? This shader allows you to draw all your sprites in one draw call instead of doing thousands of texture binds and draw calls.

Yes, but that’s for OGL3+ if I remember correctly…

@matheus23
You can fix that by either disabling GL_LINEAR, using a 2D texture array with GL_CLAMP_TO_BORDER (requires OGL 3) or adding a 1 pixel border around each image.

If I have a 2D texture array I can use GL_REPEAT anyways, can’t i?..

Ah, yes, of course. I got too fixated on eliminating the bleeding…

Are te ture arrays really just supported on ogl 3? How well is the extension supported on 2.1 drivers?

It isn’t at all. It apparently requires OpenGL 3 hardware.
http://feedback.wildfiregames.com/report/opengl/feature/GL_EXT_texture_array

theagentd - as long as your sprite batcher is big enough, my solution also only leads to a single draw call and texture bind (at the expense of pushing a few more tris).

Fyi my Mac 10.6.8 (GL 2.1) supports the texture arrays extension. I wouldn’t count on using it though, for maximum compatibility.

:-\ not supported by roughly half of all users… doesn’t look good :frowning:

I plan on supporting ogl 2.1hardware… how would i solve the problem with the filtering then?

That’s most likely because your hardware supports OGL3 but the Mac driver does not. Exactly what graphics card do you have?

Dilate the texture. Basically expand each texture one pixel in all 4 directions by copying the color of the edge pixels one pixel out. That way the linear filtering will bleed into the same color and you won’t get any artifacts. If you’re using mipmaps, you’ll need a much bigger border though.

To attempt to be more clear…if the part in question is to be wrapped, then the one-pixel border needs to be a copy of the opposite (logical) edge in the top,bottom, right & left cases and the corners the opposite corner. Generally since texture coordinates are sub-texel resolution the border needs extra data to simulate the sampling that would happen if it wasn’t in an atlas.