screen-reading_shaders.rst 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. Screen-reading shaders
  2. ======================
  3. Introduction
  4. ~~~~~~~~~~~~
  5. Very often it is desired to make a shader that reads from the same
  6. screen it's writing to. 3D APIs such as OpenGL or DirectX make this very
  7. difficult because of internal hardware limitations. GPUs are extremely
  8. parallel, so reading and writing causes all sort of cache and coherency
  9. problems. As a result, not even the most modern hardware supports this
  10. properly.
  11. The workaround is to make a copy of the screen, or a part of the screen,
  12. to a back-buffer and then read from it while drawing. Godot provides a
  13. few tools that makes this process easy!
  14. TexScreen shader instruction.
  15. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  16. Godot [[Shader]] has a special instruction, "texscreen", it takes as
  17. parameter the UV of the screen and returns a vec3 RGB with the color. A
  18. special built-in varying: SCREEN\_UV can be used to obtain the UV for
  19. the current fragment. As a result, this simple 2D fragment shader:
  20. ::
  21. COLOR=vec4( texscreen(SCREEN_UV), 1.0 );
  22. results in an invisible object, because it just shows what lies behind.
  23. The same shader using the visual editor looks like this:
  24. .. image:: /img/texscreen_visual_shader.png
  25. TexScreen Example
  26. ~~~~~~~~~~~~~~~~~
  27. Texscreen instruction can be used for a lot of things. There is a
  28. special demo for *Screen Space Shaders*, that you can download to see
  29. and learn. One example is a simple shader to adjust brightness, contrast
  30. and saturation:
  31. ::
  32. uniform float brightness=1.0;
  33. uniform float contrast=1.0;
  34. uniform float saturation=1.0;
  35. vec3 c = texscreen(SCREEN_UV);
  36. c.rgb = mix(vec3(0.0),c.rgb,brightness);
  37. c.rgb = mix(vec3(0.5),c.rgb,contrast);
  38. c.rgb = mix(vec3(dot(vec3(1.0),c.rgb)*0.33333),c.rgb,saturation);
  39. COLOR.rgb=c;
  40. Behind The Scenes
  41. ~~~~~~~~~~~~~~~~~
  42. | While this seems magical, it's not. The Texscreen instruction, when
  43. first found in a node that is about to be drawn, does a full-screen
  44. copy to a back-buffer. Subsequent nodes that use texscreen() in
  45. shaders will not have the screen copied for them, because this ends up
  46. being very inefficient.
  47. | As a result, if shaders that use texscreen() overlap, the second one
  48. will not use the result of the first one, resulting in unexpected
  49. visuals:
  50. .. image:: /img/texscreen_demo1.png
  51. In the above image, the second sphere (top right) is using the same
  52. source for texscreen() as the first one below, so the first one
  53. "dissapears", or is not visible.
  54. To correct this, a
  55. `BackBufferCopy <https://github.com/okamstudio/godot/wiki/class_backbuffercopy>`__
  56. node can be instanced between both spheres. BackBufferCopy can work by
  57. either specifying a screen region or the whole screen:
  58. .. image:: /img/texscreen_bbc.png
  59. With correct back-buffer copying, the two spheres blend correctly:
  60. .. image:: /img/texscreen_demo2.png
  61. Back-Buffer Logic
  62. ~~~~~~~~~~~~~~~~~
  63. So, to make it clearer, here's how the backbuffer copying logic works in
  64. Godot:
  65. - If a node uses the texscreen(), the entire screen is copied to the
  66. back buffer before drawing that node. This only happens the first
  67. time, subsequent nodes do not trigger this.
  68. - If a BackBufferCopy node was processed before the situation in the
  69. point above (even if texscreen() was not used), this behavior
  70. described in the point above does not happen. In other words,
  71. automatic copying of the entire screen only happens if texscreen() is
  72. used in a node for the first time and no BackBufferCopy node (not
  73. disabled) was found before in tree-order.
  74. - BackBufferCopy can copy either the entire screen or a region. If set
  75. to only a region (not the whole screen) and your shader uses pixels
  76. not in the region copied, the result of that read is
  77. [STRIKEOUT:undefined] (most likely garbage from previous frames). In
  78. other words, it's possible to use BackBufferCopy to copy back a
  79. region of the screen and then use texscreen() on a different region.
  80. Avoid this behavior!
  81. *Juan Linietsky, Ariel Manzur, Distributed under the terms of the `CC
  82. By <https://creativecommons.org/licenses/by/3.0/legalcode>`__ license.*