How to make a texture scroll over a pert of tileset?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By nadomodan

I want to achieve this kind of effect:
enter image description here

with a tileset and and 16x16 texture of eyes, I have this so far but don’t know how to achieve this effect:
enter image description here

Can you help me with the shader code, or is there another way to do this?

:bust_in_silhouette: Reply From: kidscancode

This should get you started:

shader_type canvas_item;

uniform float speed;

void fragment() {
    COLOR.rgb = texture(TEXTURE, vec2(UV.x, UV.y + TIME/speed)).rgb;
}
:bust_in_silhouette: Reply From: Akorian

A few things in addition to @kidscancode’s correct, but minimal answer.

As explanation: you modify the coordinate at which the texture is read for each pixel (only for your eyes-texture, though).

Also I want to note that in your example, the masking seems to be incorrect. It looks like there are transparent pixels in the base texture which are also red, causing the eye texture to be displayed there aswell.

They don’t show up for these lines

col.rgb = vec3(abs(sin(TIME*3.0)));
col.rg = UV;

because these don’t change the pixel’s alpha value.

This one, however, overwrites the pixel’s alpha, aswell, causing you to see all masked pixels (even ones that are transparent)

col = tex;

Another thing you might want to avoid:

if(<some float variable> == <some constant>)

Because of inaccuracies or rounding errors == might not always work.
Personally I’d use something like (a >= 0.98f) just to be safe.

And lastly, looking at the UVs you might run into trouble with stretching for your eye-texture because of the UV difference. (it also looks like it in the 2nd gif you posted)

Keep us updated on whether or not it works.

I DID IT!
video

shader_type canvas_item;
render_mode unshaded;

uniform sampler2D eyes : hint_albedo;

void fragment()
{
vec4 col = texture(TEXTURE, UV);
if (col.r >= 0.98)
	col.rgb = vec4(texture(eyes,
	vec2(fract(SCREEN_UV.x*40.0-sin(TIME+1.5)),
	fract(SCREEN_UV.y*22.5+sin(TIME))
	))).rgb;
	COLOR = col;
}

nadomodan | 2018-05-21 12:19

Great to hear!

The factors 40 and 22.5 seem a bit arbitrary, did you calculate them or adjust them manually? You might run into problems if your texture size changes.

There is a way to calculate these using the dimensions of those text inside the shader.

Akorian | 2018-05-21 16:03

Right, should’ve made the shader calculate it so it works for everything. My game is 640x360 pixels, I divided that by 16, eyes texture is 16x16

nadomodan | 2018-05-21 16:14

I think it’s dependent on the size of the atlas texture that’s used for the tilemap and the size of your eye texture. (Unless you’re using this as an fullscreen postprocess shader and not an object shader)

If you need any more help, let me know.

Akorian | 2018-05-21 16:35