Need help with shader (tiled texture) (SOLVED)

So I’m trying to learn a bit of shader and the first thing that I want to do with shader is a tiled texture for background.
For the base, I experiment with @Pkeod example.
Already the first try is an abomination and I don’t understand why. Simple 16x16 px block scaled x10 times.

varying mediump vec2 var_texcoord0;
uniform lowp sampler2D texture_sampler;
uniform lowp vec4 tint;
void main()
{
    lowp vec2 uv = vec2(var_texcoord0.x * 10, var_texcoord0.y * 10);
    gl_FragColor = tint * texture2D( texture_sampler, uv);
}

What can create that empty padding and wrong size blocks?

What does the atlas the image is on look like?

2 Likes

I found the perp. Default “Extrude Borders = 2” was messing with it.
I didn’t notice previously that atlas has those too.

2 Likes

Hah, there was a very long argument about making that the default setting on atlases. 95% of the time it is helpful, fixing artifacts at the edges of scaled images, but then there are odd cases like this where it is not what you want.

Oh, and that would also increase the size of your image in the atlas, bumping the atlas size up to 32x32, causing the empty space (which I’m sure you already figured out).

4 Likes

I removed “(solved)” from title because it didn’t end there.
Taking previous stage further I tried to apply it to actual background I want to get tiled.
And that get empty places (no extrude borders):


Space seems the same size as in atlas.

Shader:

varying mediump vec2 var_texcoord0;
uniform lowp sampler2D texture_sampler;
uniform lowp vec4 tint;
uniform lowp vec4 scale;
uniform lowp vec4 offset;

void main()
{
   // Pre-multiply alpha since all runtime textures already are
   lowp vec2 uv = vec2(var_texcoord0.x *scale.x +offset.x, var_texcoord0.y *scale.y +offset.y);
   gl_FragColor = tint * texture2D( texture_sampler, uv);
}

Does it come from width (512) not being power of 2? if so, how can I make shader to take those 512px (512/529) in count. It would be easy to give calculated proportion from closest power of 2 if that can fix the thing.

width (512) not being power of 2

512 is power of two. But as you can see in your atlas view, your actual image you have in there is <512 pixels wide. So it’s going to look weird.

It is ofc possible to fiddle with the shader to make it work, but the easiest way is to make the source images a power of two size (E.g. 512x256) for instance with Photoshop.

My bad, long time not using math I thought power of 2 means it should give int from square root.
And atlas showing 512 instead of actual 384 wasn’t helping.
How can I make 384x216 into power of 2 (and maintain pixel art)?

Well, either cut some pixels from the 384 -> 256.
Or, add some pixels 384 -> 512.

I’d do it in Photoshop, and then retouch the seams, to make sure it still tiles.

1 Like

Even though this example picture is pretty simple and doable, but it’s pretty much not an option for me in other situations since I’m not an visual artist. And that would mean work around Defold shortcoming.
Since Defold force textures to be power of 2, there should be a way to nullify it at least in shader.

Well, given that your image is the only one in the atlas, and it’s width is 384 and the atlas width is 512, you’ll know that the UV coordinates for the sprite will go from 0 to 0.75 (384/512).

So if you do a modulo, on the uv coordinate, it should wrap around:

(untested code)

uv = mod(uv, vec2(0.75, 1.0));
2 Likes

THANK YOU!!! It works.

varying mediump vec2 var_texcoord0;

uniform lowp sampler2D texture_sampler;
uniform lowp vec4 tint;
uniform lowp vec4 size; //percentage (actualSize/atlasSize) (x, y)
uniform lowp vec4 scale;
uniform lowp vec4 offset;

void main()
{
    lowp vec2 uv = vec2(var_texcoord0.x *scale.x +offset.x, var_texcoord0.y *scale.y +offset.y);
    uv = vec2(mod(uv.x, size.x), mod(uv.y, size.y));
    gl_FragColor = tint * texture2D( texture_sampler, uv);
}
2 Likes