Screen-reading shaders

    The workaround is to make a copy of the screen, or a part of the screen, to a back-buffer and then read from it while drawing. Godot provides a few tools that make this process easy!

    SCREEN_TEXTURE built-in texture

    Godot has a special texture, “SCREEN_TEXTURE” (and “DEPTH_TEXTURE” for depth, in the case of 3D). It takes as argument the UV of the screen and returns a vec3 RGB with the color. A special built-in varying: SCREEN_UV can be used to obtain the UV for the current fragment. As a result, this simple 2D fragment shader:

    results in an invisible object, because it just shows what lies behind.

    The reason why textureLod must be used is because, when Godot copies back a chunk of the screen, it also does an efficient separatable gaussian blur to its mipmaps.

    This allows for not only reading from the screen, but reading from it with different amounts of blur at no cost.

    Behind the scenes

    While this seems magical, it’s not. The SCREEN_TEXTURE built-in, when first found in a node that is about to be drawn, does a full-screen copy to a back-buffer. Subsequent nodes that use it in shaders will not have the screen copied for them, because this ends up being inefficient.

    As a result, if shaders that use SCREEN_TEXTURE overlap, the second one will not use the result of the first one, resulting in unexpected visuals:

    In the above image, the second sphere (top right) is using the same source for SCREEN_TEXTURE as the first one below, so the first one “disappears”, or is not visible.

    In 3D, this is unavoidable because copying happens when opaque rendering completes.

    ../../_images/texscreen_bbc.png

    With correct back-buffer copying, the two spheres blend correctly:

    So, to make it clearer, here’s how the backbuffer copying logic works in Godot:

    • If a node uses the SCREEN_TEXTURE, the entire screen is copied to the back buffer before drawing that node. This only happens the first time; subsequent nodes do not trigger this.
    • If a BackBufferCopy node was processed before the situation in the point above (even if SCREEN_TEXTURE was not used), the behavior described in the point above does not happen. In other words, automatic copying of the entire screen only happens if SCREEN_TEXTURE is used in a node for the first time and no BackBufferCopy node (not disabled) was found before in tree-order.

    DEPTH_TEXTURE

    For 3D Shaders, it’s also possible to access the screen depth buffer. For this, the DEPTH_TEXTURE built-in is used. This texture is not linear; it must be converted via the inverse projection matrix.