Complex 2D Wall Transparency

Godot Version

4.2

My Problem

Hi, I am making a 2d top down game and I would like to implement some wall transparency, but I struggle on how to achieve that.

Here is the thing :

Figure 1 : the scene with the wall
Figure 2 : what I don’t want. I do not want to just make my wall transparent
Figure 3 : what I want. I want to reveal what is behind the wall, I want to make the wall - and all that is in front of this wall - transparent.

What I tried, without success

I ended up with a solution that seemed to work :

Each wall is made as follow :

┖╴BackBufferCopy
    ┠╴Sprite2DWall
    ┖╴Sprite2DMask
  • The BackBufferCopy has a z_index of 1 (the same as the characters) and is y sorted. Its copy mode is Viewport
  • The Sprite2DWall has the texture of the wall, with a z_index of 0 (relatively to its parent) and is y sorted
  • The Sprite2DMask has a z_index of 2 (non relative), has the texture of the wall and is not y sorted. It has a shader.

The code of the shader is :

shader_type canvas_item;

uniform sampler2D screen_texture: hint_screen_texture;

void fragment() {
	COLOR.rgb = texture(screen_texture, SCREEN_UV).rgb;
}

So, basically, when we render the scene :

  1. The background is drawn
  2. The light blue character is drawn
  3. The wall is rendered, so the current screen display is back buffered. This current screen display only contains the background and the light blue character
  4. The Sprite2DWall is rendered so a wall is drawn
  5. The dark blue character is drawn
  6. The Sprite2DMask is rendered. Its shader makes it take the colors of the display which was back-buffered in step 1, so the sprite appears as what is behind the wall : background and light blue character

Everything works perfectly… for now.

When I add another wall in the scene, it does not work anymore. As I understand, the problem is that the Sprite2DMasks will all take the colors of the last back-buffered display.

So, when we render this scene…

  1. Background is drawn
  2. Light blue character is drawn
  3. Top wall is rendered so we back-buffer the current display
  4. Top wall Sprite2DWall is drawn
  5. Dark blue character is drawn
  6. Bottom wall is rendered so we back-buffer the current display
  7. Bottom wall Sprite2DWall is drawn
  8. Top wall Sprite2DMask is drawn
  9. Bottom wall Sprite2DMask is drawn

On step 8, the top wall Sprite2DMask takes the colors of the last back-buffered display (which was in step 6). This displays contained background, light blue character, top wall and dark blue character. So the top wall Sprite2DMask does not mask anymore the top wall…

Questions

  • Is there a standard way to achieve this particular wall transparency ?
  • Is there a way to “redirect” the Sprite2DMask on the correct back-buffered display instead of the last one ?