Shader effect by hight on the sprite

Godot Version

v4.6.1

Question

I am trying to use a shader to represent a % attribute on an object and I'm running into an issue that seems to indicate that there is something I don't understand. I have a uniform set for the shader called amount_percentage which I set in the object whenever the value updates. Then in the fragment method for the shader I have the following code:

void fragment() {
	if (UV.y > amount_percentage && COLOR.a != 0.0) {
			COLOR.rgb = texture(TEXTURE, UV).rgb * 0.4;
		}
}

What I think this is supposed to do:
–This is called on each pixel. For each pixel I’m expecting it to ask if the pixels height (taken as a % of the height of the TileMapLayer tile I’m drawing) whether or not it’s greater than the provided percentage. If it does, I’m expecting it to render that pixel as if it were 60% darker.

What seems to actually be happening:
-If the percentage drops below 1.0 to any extent, the entire tile (except the transparent parts) is darkened by 60%.

Now, if I instead tell it to set the darkening to be based on height (I.e. * UV.y instead of 0.4) I do get the expected gradient of darkness over the tile (the whole tile so long as amount_percentage is less than 1.0) so I do know that UV.y is referring to the pixels height but there is something about the logic of how it’s applied seems to make it so that if the conditional triggers for any pixel it triggers for all of them.

Does anyone know the best way to accomplish what I am trying to do, or what I’m not understanding about how this function is called?

0-1 UV range is distributed across the whole atlas. Each individual tile will take only a part of this space, depending of how the tiles are arranged in the atlas. Use REGION_RECT shader built-in to get the actual uv space occupied by the drawn tile.

That seems likely to be the issue and would explain why everything is getting shaded. I’m a bit less certain about the application even after doing some research for examples. Do you know a good example using TileMapLayers or would I have to convert to using a sprite?

shader_type canvas_item;

uniform float coverage: hint_range(0.0, 1.0) = 0.5;
uniform vec4 coverage_color: source_color = vec4(1.0, 0.0, 0.0, 1.0);

void fragment() {
	COLOR.rgb = mix(COLOR.rgb, COLOR.rgb * coverage_color.rgb, step(UV.y, REGION_RECT.y + REGION_RECT.w * coverage));
}

tile_uv

1 Like

Thank you. That example was very helpful