Browse Source

Merge pull request #1795 from GDquest/post-processing-tut-proofing

Proofed the custom_postprocessing tutorial
Max Hilbrunner 6 years ago
parent
commit
f1bbf4cd83
1 changed files with 77 additions and 84 deletions
  1. 77 84
      tutorials/viewports/custom_postprocessing.rst

+ 77 - 84
tutorials/viewports/custom_postprocessing.rst

@@ -1,81 +1,76 @@
 .. _doc_custom_postprocessing:
 
-Custom post-processing 
+Custom post-processing
 ======================
 
 Introduction
 ------------
 
-Godot provides many post-processing effects out of the box including, Bloom, DOF, and SSAO.
-Sometimes you will want to write your own post-processing effect. This can be done easily
-in Godot by rendering your scene into a :ref:`Viewport <class_Viewport>` and then rendering the 
-:ref:`Viewport's <class_Viewport>` :ref:`texture <class_ViewportTexture>` to a full screen quad. 
+Godot provides many post-processing effects out of the box including, Bloom, DOF, and SSAO. Sometimes you
+want to write your own custom effect. Here's how you can do so.
 
-.. note:: At the time of writing Godot does not support rendering to multiple buffers at the same 
-          time so the post-processing shader will not have access to normals, or anything else. 
-          You only have access to the fullscreen color texture. 
+Post-processing effects are shaders applied to a frame after Godot rendered it. You first want to render
+your scene into a :ref:`Viewport <class_Viewport>`, then render the ``Viewport``
+inside a :ref:`ViewportTexture <class_ViewportTexture>` and show it on the screen.
 
-Screen reading shaders
-----------------------
+The easiest way to implement a custom post-processing shader is to use Godot's built-in ability to read from
+the screen texture. If you're not familiar with this, you should read the :ref:`Screen Reading Shaders
+Tutorial <doc_screen-reading_shaders>` first.
 
-Before starting, a brief note on screen reading shaders is in order.
+.. note::
 
-The easiest way to do a custom post-processing shader is to use Godot's built-in ability to read
-from the screen texture. In order to take advantage of this you simply render an object over the 
-entire scene (a sprite in 2D or a quad in 3D). And use ``texture(SCREEN_TEXTURE, SCREEN_UV)`` 
-in the shader. Multi-pass post-processing shaders can even be used with a 
-:ref:`BackBufferCopy <class_BackBufferCopy>` node. For more information on how do to this see the 
-:ref:`Screen Reading Shaders Tutorial <doc_screen-reading_shaders>`.
+    At the time of writing Godot does not support rendering to multiple buffers at the same time. Your
+    post-processing shader will not have access to normals or other render passes. You only have
+    access to the rendered frame.
 
-Single pass
------------
+Single pass post-processing
+---------------------------
 
-The primary benefit to using a :ref:`Viewport <class_Viewport>` is that you have full control over 
-the rendering of the scene (including how frequently to update it) and you can take advantage of 
-using the :ref:`ViewportContainer <class_ViewportContainer>` to render 3D objects within a 2D root scene.
+You will need a ``Viewport`` to render your scene to, and a scene to render your
+``Viewport`` on the screen. You can use a :ref:`ViewportContainer
+<class_ViewportContainer>` to display your ``Viewport`` on the entire screen or inside
+another :ref:`Control <class_Control>` node.
 
-First we need a :ref:`Viewport <class_Viewport>` to render our scene to. Then we need a scene that can 
-render our :ref:`Viewport <class_Viewport>`. This can either be a 2D or 3D scene. The benefit 
-of a 2D scene is it is easy to set up a fullscreen :ref:`ViewportContainer <class_ViewportContainer>` 
-to display our :ref:`Viewport <class_Viewport>`. 
+.. note::
 
-For this demo let's use a :ref:`Node2D <class_Node2D>` with a 
-:ref:`ViewportContainer <class_ViewportContainer>` and finally a :ref:`Viewport <class_Viewport>`. 
+    Rendering using a ``Viewport`` gives you control over the
+    how the scene render, including the framerate, and you can use the
+    ``ViewportContainer`` to render 3D objects in a 2D scene.
 
-Your hierarchy should look like this:
+For this demo we will use a :ref:`Node2D <class_Node2D>` with a ``ViewportContainer`` and finally a
+``Viewport``. Your Node tab should look like this:
 
 .. image:: img/post_hierarchy1.png
 
-Inside the :ref:`Viewport <class_Viewport>` you can have whatever you want. This will contain 
-your main scene. For this tutorial we will use a field of random boxes.
+Inside the ``Viewport`` you can have whatever you want. This will contain
+your main scene. For this tutorial we will use a field of random boxes:
 
 .. image:: img/post_boxes.png
 
-In order to take advantage of the :ref:`Viewport <class_Viewport>`, attach a material to the 
-:ref:`ViewportContainer <class_ViewportContainer>`. 
+Add a new a :ref:`ShaderMaterial <class_ShaderMaterial>` to the ``ViewportContainer``, and assign a new
+shader resource to it. You can access your rendered ``Viewport`` with the built-in ``TEXTURE`` uniform.
 
-The benefit of using the :ref:`ViewportContainer <class_ViewportContainer>` is that the 
-:ref:`Viewport <class_Viewport>` can be accessed easily in the shader with the built-in 
-``TEXTURE`` uniform. You can choose not to use a :ref:`ViewportContainer <class_ViewportContainer>`, 
-but if you do so you will need to create your own uniform in the shader and pass the 
-:ref:`Viewport <class_Viewport>` texture in manually. To do so, add a uniform to the shader you use.
+.. note::
 
-::
+    You can choose not to use a ``ViewportContainer``, but if you do so you will
+    need to create your own uniform in the shader and pass the ``Viewport`` texture in
+    manually, like so:
 
-  //In Godot Shader
-  uniform sampler2D ViewportTexture;
+    ::
 
-And you can pass the texture into the shader from GDScript like so:
+      // Inside the Shader
+      uniform sampler2D ViewportTexture;
 
-::
+    And you can pass the texture into the shader from GDScript like so:
+
+    ::
 
-  #In Gdscript
-  func _ready():
-    $Sprite.material.set_shader_param("ViewportTexture", $Viewport.get_texture())
+      # In GDScript
+      func _ready():
+        $Sprite.material.set_shader_param("ViewportTexture", $Viewport.get_texture())
 
-Now, assuming you are using a :ref:`ViewportContainer <class_ViewportContainer>`, add a 
-:ref:`ShaderMaterial <class_ShaderMaterial>` to the :ref:`ViewportContainer <class_ViewportContainer>`
-and add the following code.
+Copy the following code to your shader. The above code is a single pass edge detection filter, a
+`Sobel filter <https://en.wikipedia.org/wiki/Sobel_operator>`_.
 
 ::
 
@@ -94,52 +89,50 @@ and add the following code.
 	  COLOR.xyz = col;
   }
 
-The above code is for a single pass edge detection filter in this case we are using a 
-`Sobel filter <https://en.wikipedia.org/wiki/Sobel_operator>`_. It reads pixels from a screen in a 
-9x9 grid around the current pixel and adds them together. What makes it interesting is that 
-it assigns weights to each pixel; +1 for each of the eight around the center and -8 for the 
-center pixel. The choice of weights is called a "kernel". You can use different kernels to
-achieve all kinds of different effects.
+.. note::
 
-.. image:: img/post_outline.png
+    The Sobel filter reads pixels in a 9x9 grid around the current pixel and adds them together, using weight.
+    What makes it interesting is that it assigns weights to each pixel; +1 for each of the eight around the
+    center and -8 for the center pixel. The choice of weights is called a "kernel". You can use different
+    kernels to create edge detection filters, outlines, and all sorts of effects.
 
-Multi-pass
-----------
+    .. image:: img/post_outline.png
 
-Multi-pass post-processing is useful for effects like blur which can be made significantly 
-faster if done in two passes or for other effects that require the output of the previous 
-stage of post-processing. It is done using the same method as single-pass post-processing
-with the added complication that you need to be aware of the order in which the 
-:ref:`Viewports <class_Viewport>` are rendered.
+Multi-pass post-processing
+--------------------------
 
-In order to make a multi-pass post-processing shader you stack :ref:`Viewports <class_Viewport>`. 
-In the example above you rendered the contents of one :ref:`Viewport <class_Viewport>` into 
-the root :ref:`Viewport <class_Viewport>` with a :ref:`ViewportContainer <class_ViewportContainer>`. 
-You can do the same thing for a multi-pass shader. Just render the contents of one 
-:ref:`Viewport <class_Viewport>` into another and then render the contents of that 
-:ref:`Viewport <class_Viewport>` into the root :ref:`Viewport <class_Viewport>`.
+Some post-processing effects like blur are resource intensive. If you break them down in multiple passes
+however, you can make them run a lot faster. In a multipass material, each pass takes the result from the
+previous pass as an input and processes it.
 
-Your scene hierarchy should look something like this
+To make a multi-pass post-processing shader, you stack ``Viewport`` nodes. In the example above you
+rendered the content of one ``Viewport`` object into the root ``Viewport``, through a ``ViewportContainer``
+node. You can do the same thing for a multi-pass shader by rendering the content of one ``Viewport`` into
+another and then rendering the last ``Viewport`` into the root ``Viewport``.
+
+Your scene hierarchy will look something like this:
 
 .. image:: img/post_hierarchy2.png
 
-Godot will render the child :ref:`Viewport <class_Viewport>` first, so if the order matters for 
-your shaders make sure that you assign the material you want used first to the lowest 
-:ref:`ViewportContainer <class_ViewportContainer>` in the tree.
+Godot will render the bottom ``Viewport`` node first. So if the order of the passes matters for your
+shaders, make sure that you assign the shader you want to apply first to the lowest ``ViewportContainer`` in
+the tree.
+
+.. note::
 
-.. note:: You can also render your Viewports seperately without nesting them like this. You just 
-          need to use two Viewports and render them in the proper order.
+    You can also render your Viewports seperately without nesting them like this. You just
+    need to use two Viewports and to render them one after the other.
 
-Everything else is the same as with the single-pass post-processing shader.
+Besides the node structure, the steps are the the same as with the single-pass post-processing shader.
 
-As an example, you could write a full screen Gaussian blur effect by attaching the following
-pieces of code to each of the :ref:`ViewportContainers <class_ViewportContainer>`. For this
-example, order does not matter.
+As an example, you could write a full screen Gaussian blur effect by attaching the following pieces of code
+to each of the :ref:`ViewportContainers <class_ViewportContainer>`. The order in which you apply the shaders
+does not matter:
 
 ::
-  
+
   shader_type canvas_item;
-  
+
   //Blurs the screen in the X-direction
   void fragment() {
 	  vec3 col = texture(TEXTURE, SCREEN_UV).xyz * 0.16;
@@ -155,9 +148,9 @@ example, order does not matter.
   }
 
 ::
-  
+
   shader_type canvas_item;
-  
+
   //Blurs the screen in the Y-direction
   void fragment() {
 	  vec3 col = texture(TEXTURE, SCREEN_UV).xyz * 0.16;
@@ -176,4 +169,4 @@ Using the above code you should end up with a full screen blur effect like below
 
 .. image:: img/post_blur.png
 
-For more information on how :ref:`Viewports <class_Viewport>` work see the :ref:`Viewports Tutorial <doc_viewports>`.
+For more information on how ``Viewport`` nodes work see the :ref:`Viewports Tutorial <doc_viewports>`.