TileMap item vertex

Godot Version

v4.3.stable.official [77dcf97d8]

Question

I’m implementing a simple shader for tilemap. It gets the tilemap vertex and if the mouse position is within the tile, it makes the tile red.

How it works: it assumes VERTEX gives only the top left corner position and checks the mouse position according to that.

However, I think, when you rotate the tile when placing by TileMap painting, the VERTEX given also rotates. So the upper left corner is upper right corner, if you rotate the tile clockwise, etc… And this brokes the shader code. Because it assumes the VERTEX point is always upper left corner.

How can I overcome this issue? Is there a way to get the upper left corner as vertex always, regardless of rotation? Or is there a way to pass the rotation info to shader somehow so that it can be checked within the shader code?

Thanks,

shader_type canvas_item;

varying flat vec2 vertexPos;
uniform vec2 globalMousePos;

void vertex() {
	vertexPos = (MODEL_MATRIX * vec4(VERTEX, 0.0, 1.0)).xy;
}

void fragment() {
	// Called for every pixel the material is visible on.
	float isWithinY = step(vertexPos.y, globalMousePos.y) * step(globalMousePos.y, vertexPos.y + 64.);
	float isWithinX = step(vertexPos.x, globalMousePos.x) * step(globalMousePos.x, vertexPos.x + 64.);
	float isWithin = isWithinY * isWithinX;
    // Sample the texture color
    vec4 textureColor = texture(TEXTURE, UV);

    // Only change the color if the mouse is within the rectangle
    if (isWithin == 1.0) {
        COLOR.r = 1.0; // Set color to red when within
    } 
	else {
        COLOR = textureColor; // Keep the original texture color if not within
    }
}```

I had the same issue, but did not find any other solution than to have a separate tile for each rotation… seems like it is not the optimal solution but at least it works.

I am sure there is a way to pass tile rotation to the shader, but could not find it.

I did some research on how shaders work and then changed the shader algorithm to make it work properly, regardless of the rotation.

For vertexPos, using flat type variable causes this problem because you only have the position of one vertex (which is the Provoking vertex) for each tile. And the position of this vertex changes when the tile is rotated.

If you use smooth type variable for vertexPos; for each pixel you’ll get the interpolated vertex position which corresponds to their actual world position because it’s a 2D square shown on the screen.

So what I do is:

  • vertexPos is declared as smooth type
  • top_left and bot_right corner position of that tile is sent to shader - this is something to do in the game logic.
  • Check if vertexPos is in the box defined by top_lef and bot_right values as corner positions.
varying smooth vec2 vertexPos;
uniform vec2 top_left;
uniform vec2 bot_right;

void vertex() {
	vertexPos = (MODEL_MATRIX * vec4(VERTEX, 0.0, 1.0)).xy;
}

void fragment() {
	//check if the pixel is within the box defined by top_left & bot_right cornet positions
	float isWithinY = step(top_left.y, vertexPos.y) * step(vertexPos.y, bot_right.y);
	float isWithinX = step(top_left.x, vertexPos.x) * step(vertexPos.x, bot_right.x);
	float isWithin = isWithinY *  isWithinX;

	if (isWithin == 1.0) { // if the pixel is within the box, which means pixel belongs to the tile
		//add your shader code here
	}
}

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.