I developed a basic understanding of shaders but I cannot wrap my head around screen shaders and there seems to be a noticeable lack of tutorials on it :/ I read this page multiple times: https://docs.godotengine.org/en/stable/tutorials/shaders/screen-reading_shaders.html but it's not nearly detailed enough for me to understand how this works.

So, I would really appreciate if someone could help with this:

  1. What information is actually taken from screen_uv? I get that the values go from 0.0 -> 1.0 from the topleft in each axis. However, a CanvasLayer with a ColorRect gets ignored for some reason? Or do we only apply the screenshader to elements below it ((or elements before it in the scene tree, or elements with a lower z index)?

  2. I tried to use visual shaders to get some information for each step, for example I have this:
    visual shader
    And I guess the shader preview just isn't working? Expanding the other nodes doesn't do anything either. Shouldn't the input in the image show a UV image like the normal UV information? Also, when using visual shaders with the Texture2D node, do I need the SamplerPort or the screen option? I have never seen that mentioned anywhere (in fact, nobody covers visual shaders)

  3. Still from the image above, I get that I am taking the red values from the image below the ColorRect and multiply it with the x value of the screen_uv, which works and I get values that get lighter the further right the screen goes. But when I try to limit the alpha values it gets ignored. I assume I am getting the alpha values from the ColorRect but I am not sure what to do about it.

In more general terms, does anyone know of a tutorial that explains screen shaders? I feel like I am figuring things out by blindly bashing things together which is super frustrating.

oh also, one minor but very annoying thing: Why can't I lock the CanvasLayer in the above example? Clicking on the lock symbol doesn't do anything and it makes it impossible to move things around in the editor

    izNoob as far as I know from my extensive screen-shading experience, it's an esoteric type of art that you can never "understand", but feel. to master it, you have to embrace the way of the blind swordsman. don't try to think and analyze the patterns, only recognize what works and what doesn't, feel the movement of the pixels. eventually, you will become the force the pixels answer to. wisdom by a million cuts.

    you could also read a book. i haven't gotten around to doing that myself.

    1. as far as I understand, SCREEN_UV translates the root viewport resolution to values between 0.0 - 1.0. (i'm pretty sure this is called normalizing)
    2. i have never used visual shaders in my life.
      this format won't let me skip to 3 in a numbered list.
    3. I don't think you can yank alpha values from SCREEN_UV if that was your intention.

      izNoob i don't know of any, no. i wasn't kidding about that "blind swordsman" philosophy. i've been winging it for a couple years now.

      you could spend some time studying the book of shaders and see if that helps give you some clues. it helped me a lot in screen-shading, even if it doesn't teach a single thing about that specific subject.

      izNoob There is no such thing as screen shader. It's just a somewhat misleading label for a regular shader that samples the current state of framebuffer as a texture.

      Here's how it works. As each frame is drawn, the objects in your scene are rendered into the framebuffer one by one from top to bottom. If one of those objects has a shader attached that reads the screen (framebuffer) texture, in that texture it will only find things that were rendered so far, i.e. only the objects that are "below" that object.

      So if your scene looks like this:

      tilemap
      icon
      sprite (has shader that reads screen texture)
      color rect

      If sprite's shader reads the screen texture, it will only find things that were rendered thus far - i.e. tilemap and icon. Color rect will be rendered after the sprite so screen texture as read from sprite's shader will not contain it.

        Sorry I want to make sure I understand you clearly. You want a full-screen shader that reads the screen texture and then modifies it, like for a post-processing effect. Is that right?

        An important thing to note when reading from the screen is that you're never going to get anything other than full alpha value from the screen texture. That's because you're reading the color that is on the screen at that position. Even if you don't have a sprite drawing there, the background is opaque! To do things with transparency, you either need another texture or variable controlling that, or you need to do something with the colors you're given in order to determine alpha. Here I've made an example for you where the screen-reading shader only draws over "bright" parts of the screen.

        screentest.zip
        2kB

        The result looks like this:

          izNoob or some guy sending smoke signals...

          I used to do that quite often on the forums here, I recon @xyz has largely taken over that task these days tho.

          xyz I get the basics, I think. It's just that there seem to be random issues like the screen texture not containing alpha values that get in the way.

          Although, if someone else is having the same problem, here is a shader that gets rid of the background color:

          shader_type canvas_item;
          
          uniform sampler2D SCREEN_TEXTURE: hint_screen_texture, filter_linear_mipmap;
          uniform vec3 filter_color: source_color;
          
          void fragment() {
          	vec2 uv = SCREEN_UV;
          	COLOR.r = uv.x;
          	COLOR.a = texture(SCREEN_TEXTURE, uv).rgb != filter_color ? 1.0 : 0.0;
          }

          filter_color needs to be the background color of Godot (77 for r,g and b)

          Now I am wondering how to be more specific with this. Like, how to get only certain images. I am reading about the BackBufferCopy node but, once again, very little info T_T

          • xyz replied to this.

            izNoob That code won't work with semi transparent things. The alpha issue was well explained by @award. If you need alpha, render into a custom viewport and use a viewport texture. Viewport backgrounds can be made transparent.

              xyz I will investigate! Currently stuck on BackBufferCopy but at least some progress 😃