How to show only a part of a image using shadermaterial.

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

I need this for my 3D plane. I have a single png file containing several sprites and I want to show a certain sprite onto my 3D plane mesh using shadermaterial with params such as vframes(number of frames vertical), hframes(number of frames horizontally), frames(current shown frame), and texture. Basically I want a shadermaterial that works just like the 2D Sprite node’s animation properties.

I could just use a viewport and sprites to draw the spite I want and return the viewport’s texture to my 3d mesh material or manually separate the large png file into several smaller files. But that would make the game I am making run a tad bit slower. I want to use a single large png file for all my sprites so that the file will be cached during gameplay allowing better performance compared to loading many different files.

I’ve been reading the docs on shading language but I can’t seem to get an idea on how to specifically show only a part of the large png file using shaders. Please guide me senpais.

:bust_in_silhouette: Reply From: klaas

here you have a variant with texture interpolation … have’nt tested, but this is the way to go.

frameSize = vec2(0.2,0.2); // the frame size in frations ... this is a a frameset 5 x 5
frameOffset = vec2(0.4,0.2); // the frame 3rd row 2nd column
uv_to_frame = uv * frameSize; //scale uv down to frame size
uv_to_frame = mod(uv_to_frame,frameSize); //modulo uv to handle repetition
uv_to_frame += frameOffset; //shift uv to frame
vec4 texelColor = texture ( textureSampler, uv_to_frame );

// for unfiltered pixels you have to do this
uv_to_frame *= textureSize(textureSampler,0 )
vec4 texelColor = texelFetch( textureSampler, uv_to_frame,0 );

Thank you! I was able to make it thanks to your guidance :smiley:
my code looks like this:

uniform int hframe : hint_range(1,128);
uniform int vframe : hint_range(1,128);
uniform vec2 current_frame = vec2(0,0);

void fragment() {
	vec2 base_uv = (UV / vec2(float(hframe),float(vframe)));
	base_uv += current_frame/vec2(float(hframe),float(vframe));
	vec4 albedo_tex = texture(texture_albedo,base_uv);

It works, thank you so much klaas.

Xian | 2020-09-01 14:41