瀏覽代碼

Improve First 3D shader tutorial

tetrapod00 5 月之前
父節點
當前提交
287ad02f83

+ 1 - 0
tutorials/shaders/shader_reference/shading_language.rst

@@ -812,6 +812,7 @@ There are two possible interpolation qualifiers:
 | **smooth**        | The value is interpolated in a perspective-correct fashion. This is the default.|
 +-------------------+---------------------------------------------------------------------------------+
 
+.. _doc_shading_language_uniforms:
 
 Uniforms
 --------

+ 69 - 57
tutorials/shaders/your_first_shader/your_first_3d_shader.rst

@@ -63,20 +63,21 @@ Setting up
 
 Add a new :ref:`MeshInstance3D <class_MeshInstance3D>` node to your scene.
 
-In the inspector tab beside "Mesh" click "<empty>" and select "New PlaneMesh".
-Then click on the image of a plane that appears.
+In the inspector tab, set the MeshInstance3D's **Mesh** property to a new
+:ref:`PlaneMesh <class_planemesh>` resource, by clicking on ``<empty>`` and
+choosing **New PlaneMesh**. Then expand the resource by clicking on the image of
+a plane that appears.
 
-This adds a :ref:`PlaneMesh <class_planemesh>` to our scene.
+This adds a plane to our scene.
 
-Then, in the viewport, click in the upper left corner on the button that says
-"Perspective". A menu will appear. In the middle of the menu are options for how
-to display the scene. Select 'Display Wireframe'.
+Then, in the viewport, click in the upper left corner on the **Perspective** button.
+In the menu that appears, select **Display Wireframe**.
 
 This will allow you to see the triangles making up the plane.
 
 .. image:: img/plane.webp
 
-Now set ``Subdivide Width`` and ``Subdivide Depth`` of the :ref:`PlaneMesh <class_planemesh>` to ``32``.
+Now set **Subdivide Width** and **Subdivide Depth** of the :ref:`PlaneMesh <class_planemesh>` to ``32``.
 
 .. image:: img/plane-sub-set.webp
 
@@ -87,12 +88,13 @@ and thus allow us to add more detail.
 .. image:: img/plane-sub.webp
 
 :ref:`PrimitiveMeshes <class_primitivemesh>`, like PlaneMesh, only have one
-surface, so instead of an array of materials there is only one. Click
-beside "Material" where it says "<empty>" and select "New ShaderMaterial".
-Then click the sphere that appears.
+surface, so instead of an array of materials there is only one. Set the
+**Material** to a new ShaderMaterial, then expand the material by clicking on
+the sphere that appears.
 
-Now click beside "Shader" where it says "<empty>" and select "New Shader...". Leave
-the default settings, give your shader a name and click "Create".
+Now set the material's **Shader** to a new Shader by clicking ``<empty>`` and
+select **New Shader...**. Leave the default settings, give your shader a name,
+and click **Create**.
 
 Click on the shader in the inspector, and the shader editor should now pop up. You
 are ready to begin writing your first Spatial shader!
@@ -116,7 +118,7 @@ appear in the final scene. We will be using it to offset the height of each vert
 and make our flat plane appear like a little terrain.
 
 With nothing in the ``vertex()`` function, Godot will use its default vertex
-shader. We can easily start to make changes by adding a single line:
+shader. We can start to make changes by adding a single line:
 
 .. code-block:: glsl
 
@@ -130,12 +132,12 @@ Adding this line, you should get an image like the one below.
 
 Okay, let's unpack this. The ``y`` value of the ``VERTEX`` is being increased.
 And we are passing the ``x`` and ``z`` components of the ``VERTEX`` as arguments
-to ``cos`` and ``sin``; that gives us a wave-like appearance across the ``x``
-and ``z`` axes.
+to :ref:`cos() <shader_func_cos>` and :ref:`sin() <shader_func_sin>`; that gives
+us a wave-like appearance across the ``x`` and ``z`` axes.
 
-What we want to achieve is the look of little hills; after all. ``cos`` and
-``sin`` already look kind of like hills. We do so by scaling the inputs to the
-``cos`` and ``sin`` functions.
+What we want to achieve is the look of little hills; after all. ``cos()`` and
+``sin()`` already look kind of like hills. We do so by scaling the inputs to the
+``cos()`` and ``sin()`` functions.
 
 .. code-block:: glsl
 
@@ -166,30 +168,19 @@ shader, outside the ``vertex()`` function.
   uniform sampler2D noise;
 
 This will allow you to send a noise texture to the shader. Now look in the
-inspector under your material. You should see a section called "Shader Params".
-If you open it up, you'll see a section called "noise".
+inspector under your material. You should see a section called **Shader Parameters**.
+If you open it up, you'll see a parameter called "Noise".
 
-Click beside it where it says "<empty>" and select "New NoiseTexture2D". Then in
-your :ref:`NoiseTexture2D <class_noisetexture2D>` click beside where it says "Noise" and select "New
-FastNoiseLite".
-
-.. note:: :ref:`FastNoiseLite <class_fastnoiselite>` is used by the NoiseTexture2D to
-          generate a heightmap.
+Set this **Noise** parameter to a new :ref:`NoiseTexture2D <class_noisetexture2D>`.
+Then in your NoiseTexture2D, set its **Noise** property to a new
+:ref:`FastNoiseLite <class_fastnoiselite>`. The FastNoiseLite class is used by
+the NoiseTexture2D to generate a heightmap.
 
 Once you set it up and should look like this.
 
 .. image:: img/noise-set.webp
 
-Now, access the noise texture using the ``texture()`` function. ``texture()``
-takes a texture as the first argument and a ``vec2`` for the position on the
-texture as the second argument. We use the ``x`` and ``z`` channels of
-``VERTEX`` to determine where on the texture to look up. Note that the PlaneMesh
-coordinates are within the [-1,1] range (for a size of 2), while the texture
-coordinates are within [0,1], so to normalize we divide by the size of the
-PlaneMesh by 2.0 and add 0.5. ``texture()`` returns a ``vec4`` of the ``r, g, b,
-a`` channels at the position. Since the noise texture is grayscale, all of the
-values are the same, so we can use any one of the channels as the height. In
-this case we'll use the ``r``, or ``x`` channel.
+Now, access the noise texture using the ``texture()`` function:
 
 .. code-block:: glsl
 
@@ -198,10 +189,27 @@ this case we'll use the ``r``, or ``x`` channel.
     VERTEX.y += height;
   }
 
-Note: ``xyzw`` is the same as ``rgba`` in GLSL, so instead of ``texture().x``
-above, we could use ``texture().r``. See the `OpenGL documentation
-<https://www.khronos.org/opengl/wiki/Data_Type_(GLSL)#Vectors>`_ for more
-details.
+:ref:`texture() <shader_func_texture>` takes a texture as the first argument and
+a ``vec2`` for the position on the texture as the second argument. We use the
+``x`` and ``z`` channels of ``VERTEX`` to determine where on the texture to look
+up. 
+
+Since the PlaneMesh coordinates are within the ``[-1.0, 1.0]`` range (for a size
+of ``2.0``), while the texture coordinates are within ``[0.0, 1.0]``, to remap
+the coordinates we divide by the size of the PlaneMesh by ``2.0`` and add
+``0.5`` .
+
+``texture()`` returns a ``vec4`` of the ``r, g, b, a`` channels at the position.
+Since the noise texture is grayscale, all of the values are the same, so we can
+use any one of the channels as the height. In this case we'll use the ``r``, or
+``x`` channel.
+
+.. note::
+
+  ``xyzw`` is the same as ``rgba`` in GLSL, so instead of ``texture().x``
+  above, we could use ``texture().r``. See the `OpenGL documentation
+  <https://www.khronos.org/opengl/wiki/Data_Type_(GLSL)#Vectors>`_ for more
+  details.
 
 Using this code you can see the texture creates random looking hills.
 
@@ -214,7 +222,8 @@ texture, now let's learn how they work.
 Uniforms
 --------
 
-Uniform variables allow you to pass data from the game into the shader. They are
+:ref:`Uniform variables <doc_shading_language_uniforms>` allow you to pass data
+from the game into the shader. They are
 very useful for controlling shader effects. Uniforms can be almost any datatype
 that can be used in the shader. To use a uniform, you declare it in your
 :ref:`Shader<class_Shader>` using the keyword ``uniform``.
@@ -228,11 +237,11 @@ Let's make a uniform that changes the height of the terrain.
 
 Godot lets you initialize a uniform with a value; here, ``height_scale`` is set
 to ``0.5``. You can set uniforms from GDScript by calling the function
-``set_shader_parameter()`` on the material corresponding to the shader. The value
-passed from GDScript takes precedence over the value used to initialize it in
-the shader.
+:ref:`set_shader_parameter() <class_ShaderMaterial_method_set_shader_parameter>`
+on the material corresponding to the shader. The value passed from GDScript
+takes precedence over the value used to initialize it in the shader.
 
-::
+.. code-block:: gdscript
 
   # called from the MeshInstance3D
   mesh.material.set_shader_parameter("height_scale", 0.5)
@@ -245,8 +254,8 @@ the shader.
           ``get_surface_material()`` or ``material_override``.
 
 Remember that the string passed into ``set_shader_parameter()`` must match the name
-of the uniform variable in the :ref:`Shader<class_Shader>`. You can use the
-uniform variable anywhere inside your :ref:`Shader<class_Shader>`. Here, we will
+of the uniform variable in the shader. You can use the
+uniform variable anywhere inside your shader. Here, we will
 use it to set the height value instead of arbitrarily multiplying by ``0.5``.
 
 .. code-block:: glsl
@@ -264,16 +273,17 @@ especially useful for animations.
 Interacting with light
 ----------------------
 
-First, turn wireframe off. To do so, click in the upper-left of the Viewport
-again, where it says "Perspective", and select "Display Normal".
-Additionally in the 3D scene toolbar, turn off preview sunlight.
+First, turn wireframe off. To do so, open the **Perspective** menu in the
+upper-left of the viewport again, and select **Display Normal**. Additionally in
+the 3D scene toolbar, turn off preview sunlight.
 
 .. image:: img/normal.webp
 
 Note how the mesh color goes flat. This is because the lighting on it is flat.
 Let's add a light!
 
-First, we will add an :ref:`OmniLight3D<class_OmniLight3D>` to the scene.
+First, we will add an :ref:`OmniLight3D<class_OmniLight3D>` to the scene, and 
+drag it up so it is above the terrain.
 
 .. image:: img/light.webp
 
@@ -300,7 +310,7 @@ do that by passing in a second noise texture.
   uniform sampler2D normalmap;
 
 Set this second uniform texture to another :ref:`NoiseTexture2D <class_noisetexture2D>` with another
-:ref:`FastNoiseLite <class_fastnoiselite>`. But this time, check **As Normalmap**.
+:ref:`FastNoiseLite <class_fastnoiselite>`. But this time, check **As Normal Map**.
 
 .. image:: img/normal-set.webp
 
@@ -312,20 +322,19 @@ wrapping the texture around the mesh automatically.
 Lastly, in order to ensure that we are reading from the same places on the noise
 texture and the normalmap texture, we are going to pass the ``VERTEX.xz``
 position from the ``vertex()`` function to the ``fragment()`` function. We do
-that with varyings.
+that using a :ref:`varying <doc_shading_language_varyings>`.
 
-Above the ``vertex()`` define a ``vec2`` called ``tex_position``. And inside the
-``vertex()`` function assign ``VERTEX.xz`` to ``tex_position``.
+Above the ``vertex()`` define a ``varying vec2`` called ``tex_position``. And
+inside the ``vertex()`` function assign ``VERTEX.xz`` to ``tex_position``.
 
 .. code-block:: glsl
 
   varying vec2 tex_position;
 
   void vertex() {
-    ...
     tex_position = VERTEX.xz / 2.0 + 0.5;
     float height = texture(noise, tex_position).x;
-    ...
+    VERTEX.y += height * height_scale;
   }
 
 And now we can access ``tex_position`` from the ``fragment()`` function.
@@ -345,6 +354,9 @@ We can even drag the light around and the lighting will update automatically.
 
 .. image:: img/normalmap2.webp
 
+Full code
+---------
+
 Here is the full code for this tutorial. You can see it is not very long as
 Godot handles most of the difficult stuff for you.