UV inside Vertex function not matching Fragment function

Godot Version

4.5.1-stable

Question

This has me genuinely baffled so any help is immensely appreciated.

I have a texture which is a white square for the sake of testing, on which I have the following shader;

shader_type canvas_item;
render_mode unshaded;

uniform float area_start : hint_range(0.0, 1.0, 0.01) = 0.0;
uniform float area_end : hint_range(0.0, 1.0, 0.01) = 1.0;

void vertex() {
	float y = 1.0 - UV.y;
	bool inside_region = y >= area_start && y <= area_end;
	if (inside_region) {
		VERTEX.x += 50.0;
	}
}

How I would expect this to work is as follows:

  • Get ‘y’ from the UV and invert it, so the bottom of the texture should be 0.0 and the top 1.0.
  • ‘inside_region’ should return True only if ‘y’ is within the values between ‘area_start’ and ‘area_end’
  • If ‘inside_region’ is True, then offset the texture 50 units to the right.

However, when running this I get the following results:

This is when ‘area_start’ is 0.0 and ‘area_end’ is 1.0.

When ‘area_end’ is any non-one value and ‘area_start’ is 0.0.

When ‘area_end’ is 1.0 and ‘area_start’ is any non-zero value;

And finally, when both ‘area_start’ is not zero and ‘area_end’ is not one.

Now, to me, this makes no sense. How is it sheering gradually when it should be being increased by a fixed amount based on a boolean value? I even tried using the VERTEX.y value alongside a uniform for the node size to get what should be the UV.y value in the case it was wrong inside the vertex() function, but it was the same result as I both did and didn’t expect.

As said at the top of this post this has left me genuinely baffled, I have spent over an hour trying to figure out how this is causing this result and came up empty.

The thing is, when running some simmilar code inside the fragment() function I get what I expect, though I had to invert the UV.y as seen below;

COLOR.r = float(1.0 - UV.y > area_start && 1.0 - UV.y < area_end)

This results in a movable (Based off of ‘area_start’ and ‘area_end’) region which is white while the rest is blue. Why is the vertex() any different?

I want the vertex to apply the offset under the same conditions as the above.

Thanks.

vertex() function is invoked per vertex. There is total of 4 vertices in your quad. One at every corner. For top two vertices, your y will be 1.0, while for bottom two vertices it will be 0.0.

When area range is (0.0, 1.0), y will satisfy the condition for each vertex, so they all will be translated.

When area range is (0.0, <1.0), y will satisfy the condition for bottom two vertices (for whom y is 0.0), but won’t satisfy it for top two vertices (for whom y is 1.0)

When area range is is (>0.0, 1.0), y will satisfy the condition for top two vertices (for whom y is 1.0), but won’t satisfy it for bottom two vertices (for whom y is 0.0)

1 Like

Thanks so much, that makes it make sense why it behaves that way.

So is it possible to achieve something like I described? Where only a vertical slice is transformed while the rest remain in place? Or is that not possible without breaking it down into multiple smaller textures and then animate the specific textures wanted?

Originally I was trying to make a shader to animate a campfire sprite, so the intention was to see if the area was within the area of the smoke so only that can be animated (Here it would be anything above the pot), while keeping it all as one texture:

How could that be done?

Thanks.

Animate the UVs in fragment() function.

1 Like

You make a good point.

After you said that I remembered I could change the colour based off of texture, if only that had came to me sooner (COLOR = texture(TEXTURE, UV + offset)).

Thanks for the help!

1 Like

Hi,

Vertex Shaders are programs that run on vertices not fragments. The results are expected.
Whether you use a boolean or a float, doesn’t matter.

Between Vertex and Fragment shader, the varyings (position, uvs, color etc.) are interpolated over each fragment.
If one vertex has an x position of 0 and another of 50, then the fragments x positions between them goes from 0 to 50 in a linear fashion. That is how triangles are rendered.

It’s not possible to change the vertex position in the fragment shader.
You could increase the size of the sprite to include space to transform uvs and the run the program in the fragment shader using the uvs.