diff --git a/tutorials/shaders/your_first_shader/img/PBR.png b/tutorials/shaders/your_first_shader/img/PBR.png deleted file mode 100644 index cbd34f7c211..00000000000 Binary files a/tutorials/shaders/your_first_shader/img/PBR.png and /dev/null differ diff --git a/tutorials/shaders/your_first_shader/img/PBR.webp b/tutorials/shaders/your_first_shader/img/PBR.webp new file mode 100644 index 00000000000..6bf10b7f9be Binary files /dev/null and b/tutorials/shaders/your_first_shader/img/PBR.webp differ diff --git a/tutorials/shaders/your_first_shader/img/albedo.png b/tutorials/shaders/your_first_shader/img/albedo.png deleted file mode 100644 index a0e3555bc67..00000000000 Binary files a/tutorials/shaders/your_first_shader/img/albedo.png and /dev/null differ diff --git a/tutorials/shaders/your_first_shader/img/albedo.webp b/tutorials/shaders/your_first_shader/img/albedo.webp new file mode 100644 index 00000000000..1a4e0e3a568 Binary files /dev/null and b/tutorials/shaders/your_first_shader/img/albedo.webp differ diff --git a/tutorials/shaders/your_first_shader/img/dark-water.png b/tutorials/shaders/your_first_shader/img/dark-water.png deleted file mode 100644 index cc8b2dcc806..00000000000 Binary files a/tutorials/shaders/your_first_shader/img/dark-water.png and /dev/null differ diff --git a/tutorials/shaders/your_first_shader/img/dark-water.webp b/tutorials/shaders/your_first_shader/img/dark-water.webp new file mode 100644 index 00000000000..44acb9122a2 Binary files /dev/null and b/tutorials/shaders/your_first_shader/img/dark-water.webp differ diff --git a/tutorials/shaders/your_first_shader/img/frequency.webp b/tutorials/shaders/your_first_shader/img/frequency.webp new file mode 100644 index 00000000000..484734e02bb Binary files /dev/null and b/tutorials/shaders/your_first_shader/img/frequency.webp differ diff --git a/tutorials/shaders/your_first_shader/img/fresnel.png b/tutorials/shaders/your_first_shader/img/fresnel.png deleted file mode 100644 index fcee05ca57e..00000000000 Binary files a/tutorials/shaders/your_first_shader/img/fresnel.png and /dev/null differ diff --git a/tutorials/shaders/your_first_shader/img/fresnel.webp b/tutorials/shaders/your_first_shader/img/fresnel.webp new file mode 100644 index 00000000000..99abe29824a Binary files /dev/null and b/tutorials/shaders/your_first_shader/img/fresnel.webp differ diff --git a/tutorials/shaders/your_first_shader/img/normals.webp b/tutorials/shaders/your_first_shader/img/normals.webp new file mode 100644 index 00000000000..55af756e1a8 Binary files /dev/null and b/tutorials/shaders/your_first_shader/img/normals.webp differ diff --git a/tutorials/shaders/your_first_shader/img/octave.webp b/tutorials/shaders/your_first_shader/img/octave.webp new file mode 100644 index 00000000000..fdae7470d12 Binary files /dev/null and b/tutorials/shaders/your_first_shader/img/octave.webp differ diff --git a/tutorials/shaders/your_first_shader/img/plastic.png b/tutorials/shaders/your_first_shader/img/plastic.png deleted file mode 100644 index 98708043454..00000000000 Binary files a/tutorials/shaders/your_first_shader/img/plastic.png and /dev/null differ diff --git a/tutorials/shaders/your_first_shader/img/plastic.webp b/tutorials/shaders/your_first_shader/img/plastic.webp new file mode 100644 index 00000000000..c7ae807eace Binary files /dev/null and b/tutorials/shaders/your_first_shader/img/plastic.webp differ diff --git a/tutorials/shaders/your_first_shader/img/rim.png b/tutorials/shaders/your_first_shader/img/rim.png deleted file mode 100644 index 185ee54675b..00000000000 Binary files a/tutorials/shaders/your_first_shader/img/rim.png and /dev/null differ diff --git a/tutorials/shaders/your_first_shader/img/rim.webp b/tutorials/shaders/your_first_shader/img/rim.webp new file mode 100644 index 00000000000..62a38c6ac88 Binary files /dev/null and b/tutorials/shaders/your_first_shader/img/rim.webp differ diff --git a/tutorials/shaders/your_first_shader/img/set-frequency.webp b/tutorials/shaders/your_first_shader/img/set-frequency.webp new file mode 100644 index 00000000000..6b6f54adb61 Binary files /dev/null and b/tutorials/shaders/your_first_shader/img/set-frequency.webp differ diff --git a/tutorials/shaders/your_first_shader/img/specular-toon.png b/tutorials/shaders/your_first_shader/img/specular-toon.png deleted file mode 100644 index d1783f255f9..00000000000 Binary files a/tutorials/shaders/your_first_shader/img/specular-toon.png and /dev/null differ diff --git a/tutorials/shaders/your_first_shader/img/wave1.png b/tutorials/shaders/your_first_shader/img/wave1.png deleted file mode 100644 index c3fb8a3a5b7..00000000000 Binary files a/tutorials/shaders/your_first_shader/img/wave1.png and /dev/null differ diff --git a/tutorials/shaders/your_first_shader/img/wave1.webp b/tutorials/shaders/your_first_shader/img/wave1.webp new file mode 100644 index 00000000000..dbc2b75e261 Binary files /dev/null and b/tutorials/shaders/your_first_shader/img/wave1.webp differ diff --git a/tutorials/shaders/your_first_shader/img/wave2.png b/tutorials/shaders/your_first_shader/img/wave2.png deleted file mode 100644 index f489296c9ca..00000000000 Binary files a/tutorials/shaders/your_first_shader/img/wave2.png and /dev/null differ diff --git a/tutorials/shaders/your_first_shader/img/wave2.webp b/tutorials/shaders/your_first_shader/img/wave2.webp new file mode 100644 index 00000000000..7f643ecd38c Binary files /dev/null and b/tutorials/shaders/your_first_shader/img/wave2.webp differ diff --git a/tutorials/shaders/your_first_shader/img/wave3.png b/tutorials/shaders/your_first_shader/img/wave3.png deleted file mode 100644 index 28d29d10fe3..00000000000 Binary files a/tutorials/shaders/your_first_shader/img/wave3.png and /dev/null differ diff --git a/tutorials/shaders/your_first_shader/img/wave3.webp b/tutorials/shaders/your_first_shader/img/wave3.webp new file mode 100644 index 00000000000..93808e08e10 Binary files /dev/null and b/tutorials/shaders/your_first_shader/img/wave3.webp differ diff --git a/tutorials/shaders/your_first_shader/your_second_3d_shader.rst b/tutorials/shaders/your_first_shader/your_second_3d_shader.rst index 4fd12abdc03..72f29bb0ac6 100644 --- a/tutorials/shaders/your_first_shader/your_second_3d_shader.rst +++ b/tutorials/shaders/your_first_shader/your_second_3d_shader.rst @@ -3,70 +3,89 @@ Your second 3D shader ===================== -From a high-level, what Godot does is give the user a bunch of parameters that -can be optionally set (``AO``, ``SSS_Strength``, ``RIM``, etc.). These +From a high-level, what Godot does is give the user a bunch of shader parameters +that can be optionally set (``AO``, ``SSS_Strength``, ``RIM``, etc.). These parameters correspond to different complex effects (Ambient Occlusion, SubSurface Scattering, Rim Lighting, etc.). When not written to, the code is thrown out before it is compiled and so the shader does not incur the cost of -the extra feature. This makes it easy for users to have complex PBR-correct +the extra feature. This allows users to have complex PBR-correct shading, without writing complex shaders. Of course, Godot also allows you to ignore all these parameters and write a fully customized shader. -For a full list of these parameters see the :ref:`spatial shader -` reference doc. +For a full list of these parameters see the :ref:`spatial shader ` +reference doc. A difference between the vertex function and a fragment function is that the vertex function runs per vertex and sets properties such as ``VERTEX`` (position) and ``NORMAL``, while the fragment shader runs per pixel and, most importantly, sets the ``ALBEDO`` color of the :ref:`MeshInstance3D`. -Your first spatial fragment function ------------------------------------- +.. note:: + + As mentioned above, the standard use of the + fragment function in Godot is to set up different material properties and let + Godot handle the rest. In order to provide even more flexibility, Godot also + provides render modes. Render modes are set at the top of the + shader, directly below ``shader_type``. They're used to specify what sort of + functionality you want the built-in aspects of the shader to have. -As mentioned in the previous part of this tutorial. The standard use of the -fragment function in Godot is to set up different material properties and let -Godot handle the rest. In order to provide even more flexibility, Godot also -provides things called render modes. Render modes are set at the top of the -shader, directly below ``shader_type``, and they specify what sort of -functionality you want the built-in aspects of the shader to have. + For example, if you do not want to have lights affect an object, set the + render mode to ``unshaded``: -For example, if you do not want to have lights affect an object, set the render -mode to ``unshaded``: + .. code-block:: glsl -.. code-block:: glsl + render_mode unshaded; - render_mode unshaded; + You can also stack multiple render modes together. For example, if you want to + use toon shading instead of more-realistic PBR shading, set the diffuse + and specular modes to toon: -You can also stack multiple render modes together. For example, if you want to -use toon shading instead of more-realistic PBR shading, set the diffuse mode and -specular mode to toon: + .. code-block:: glsl -.. code-block:: glsl + render_mode diffuse_toon, specular_toon; - render_mode diffuse_toon, specular_toon; + This model of built-in functionality allows you to write complex custom + shaders by changing only a few parameters. -This model of built-in functionality allows you to write complex custom shaders -by changing only a few parameters. + For a full list of render modes, see the :ref:`Spatial shader reference `. -For a full list of render modes see the :ref:`Spatial shader reference -`. +Your first spatial fragment function +------------------------------------ In this part of the tutorial, we will walk through how to take the bumpy terrain from the previous part and turn it into an ocean. -First let's set the color of the water. We do that by setting ``ALBEDO``. +First, let's increase the size and subdivisions of the plane to allow for more +detail. Set the **x** and **y** properties of the :ref:`Mesh ` +to ``10.0``, and increase the **Subdivide Width** and **Subdivide Depth** +properties to ``256``. -``ALBEDO`` is a ``vec3`` that contains the color of the object. +Due to the increased size of the plane our texture coordinates will no longer +scale nicely. We'll also adjust the scaling factor to match the new size of the +mesh. + +.. code-block:: glsl + + void vertex() { + tex_position = VERTEX.xz / 10.0 + 0.5; // Scaling factor set to 10 for 10x10 mesh. + float height = texture(noise, tex_position).x; + VERTEX.y += height * height_scale; + } + + +Let's set the color of the water. We do that by setting ``ALBEDO``. ``ALBEDO`` +is a ``vec3`` that contains the color of the object. Let's set it to a nice shade of blue. .. code-block:: glsl void fragment() { + NORMAL_MAP = texture(normalmap, tex_position).xyz; ALBEDO = vec3(0.1, 0.3, 0.5); } -.. image:: img/albedo.png +.. image:: img/albedo.webp We set it to a very dark shade of blue because most of the blueness of the water will come from reflections from the sky. @@ -84,10 +103,10 @@ the reflection and the ``ALBEDO`` color. A high ``METALLIC`` almost ignores ``ALBEDO`` altogether, and looks like a mirror of the sky. While a low ``METALLIC`` has a more equal representation of sky color and ``ALBEDO`` color. -``ROUGHNESS`` increases from ``0`` to ``1`` from left to right while -``METALLIC`` increase from ``0`` to ``1`` from top to bottom. +In the example below, ``ROUGHNESS`` increases from ``0`` to ``1`` from left to +right while ``METALLIC`` increases from ``0`` to ``1`` from top to bottom. -.. image:: img/PBR.png +.. image:: img/PBR.webp .. note:: ``METALLIC`` should be close to ``0`` or ``1`` for proper PBR shading. Only set it between them for blending between materials. @@ -99,14 +118,15 @@ low as well. .. code-block:: glsl void fragment() { + NORMAL_MAP = texture(normalmap, tex_position).xyz; METALLIC = 0.0; ROUGHNESS = 0.01; ALBEDO = vec3(0.1, 0.3, 0.5); } -.. image:: img/plastic.png +.. image:: img/plastic.webp -Now we have a smooth plastic looking surface. It is time to think about some +Now we have a smooth, plastic looking surface. It is time to think about some particular properties of water that we want to emulate. There are two main ones that will take this from a weird plastic surface to nice stylized water. The first is specular reflections. Specular reflections are those bright spots you @@ -115,31 +135,22 @@ reflectance. Fresnel reflectance is the property of objects to become more reflective at shallow angles. It is the reason why you can see into water below you, but farther away it reflects the sky. -In order to increase the specular reflections, we will do two things. First, we -will change the render mode for specular to toon because the toon render mode -has larger specular highlights. - -.. code-block:: glsl - - render_mode specular_toon; - -.. image:: img/specular-toon.png - -Second we will add rim lighting. Rim lighting increases the effect of light at -glancing angles. Usually it is used to emulate the way light passes through -fabric on the edges of an object, but we will use it here to help achieve a nice -watery effect. +In order to increase the specular reflections, we will add rim lighting. Rim +lighting increases the effect of light at glancing angles. Usually it is used +to emulate the way light passes through fabric on the edges of an object, but +we will use it here to help achieve a nice watery effect. .. code-block:: glsl void fragment() { + NORMAL_MAP = texture(normalmap, tex_position).xyz; RIM = 0.2; METALLIC = 0.0; ROUGHNESS = 0.01; ALBEDO = vec3(0.1, 0.3, 0.5); } -.. image:: img/rim.png +.. image:: img/rim.webp In order to add fresnel reflectance, we will compute a fresnel term in our fragment shader. Here, we aren't going to use a real fresnel term for @@ -153,15 +164,12 @@ when you are looking at the surface head-on or at a glancing angle. float fresnel = sqrt(1.0 - dot(NORMAL, VIEW)); -And mix it into both ``ROUGHNESS`` and ``ALBEDO``. This is the benefit of -ShaderMaterials over StandardMaterial3Ds. With StandardMaterial3D, we could set -these properties with a texture, or to a flat number. But with shaders we can -set them based on any mathematical function that we can dream up. - +And mix it into both ``ROUGHNESS`` and ``ALBEDO``. .. code-block:: glsl void fragment() { + NORMAL_MAP = texture(normalmap, tex_position).xyz; float fresnel = sqrt(1.0 - dot(NORMAL, VIEW)); RIM = 0.2; METALLIC = 0.0; @@ -169,14 +177,18 @@ set them based on any mathematical function that we can dream up. ALBEDO = vec3(0.1, 0.3, 0.5) + (0.1 * fresnel); } -.. image:: img/fresnel.png +.. image:: img/fresnel.webp -And now, with only 5 lines of code, you can have complex looking water. Now that -we have lighting, this water is looking too bright. Let's darken it. This is -done easily by decreasing the values of the ``vec3`` we pass into ``ALBEDO``. -Let's set them to ``vec3(0.01, 0.03, 0.05)``. +This is the benefit of ShaderMaterials over StandardMaterial3Ds. With +StandardMaterial3D, we could set these properties with a texture, or to a flat +number. But with shaders we can set them based on any mathematical function that +we can dream up. -.. image:: img/dark-water.png +Now that we have lighting, this water is looking too bright. Let's darken it. +This is done easily by decreasing the values of the ``vec3`` we pass into +``ALBEDO``. Let's set them to ``vec3(0.01, 0.03, 0.05)``. + +.. image:: img/dark-water.webp Animating with ``TIME`` ----------------------- @@ -185,24 +197,50 @@ Going back to the vertex function, we can animate the waves using the built-in variable ``TIME``. ``TIME`` is a built-in variable that is accessible from the vertex and fragment -functions. - - -In the last tutorial we calculated height by reading from a heightmap. For this -tutorial, we will do the same. Put the heightmap code in a function called -``height()``. +functions. To create our first waves, we will offset the texture position by the +cosine of ``TIME``. .. code-block:: glsl - float height(vec2 position) { - return texture(noise, position / 10.0).x; // Scaling factor is based on mesh size (this PlaneMesh is 10×10). + void vertex() { + tex_position = VERTEX.xz; + vec2 offset = 0.01 * cos(tex_position + TIME); + tex_position = (tex_position / 10.0 + 0.5) - offset; + float height = texture(noise, tex_position).x; + VERTEX.y += height * height_scale; } -In order to use ``TIME`` in the ``height()`` function, we need to pass it in. +.. note:: + + This will result in texture coordinates that will go out of the bounds of our + noise textures and wrap around. The :ref:`NoiseTexture2D ` + we are using for **Noise** and **Normalmap** should have their :ref:`Seamless ` + property set to ``On`` at this stage, or the seams will be visible. + +This results in waves that move slowly, but not in a very natural way. The next +section will dig deeper into using shaders to create more complex effects, in +this case realistic waves, by adding a few more mathematical functions. + +Advanced effects: waves +----------------------- + +Computing Normals +~~~~~~~~~~~~~~~~~ + +We are still taking our height values directly from the noise texture at +``tex_position``. We then use this same position in ``fragment()`` to take the +corresponding normal value from our normal map. In the next section we will be +introducing functions to compute our own height values, making our normal map +invalid. This means we will have to compute them manually. + +First we will move the height calculation into its own function. Put the code +into a function called ``height()``. .. code-block:: glsl float height(vec2 position, float time) { + vec2 offset = 0.01 * cos(position + time); + return texture(noise, (position / 10.0) - offset).x; } And make sure to correctly pass it in inside the vertex function. @@ -215,32 +253,33 @@ And make sure to correctly pass it in inside the vertex function. VERTEX.y = k; } -Instead of using a normalmap to calculate normals. We are going to compute them -manually in the ``vertex()`` function. To do so use the following line of code. +We can then calculate the normal value in ``vertex()`` using the following line +of code. .. code-block:: glsl - NORMAL = normalize(vec3(k - height(pos + vec2(0.1, 0.0), TIME), 0.1, k - height(pos + vec2(0.0, 0.1), TIME))); + NORMAL = normalize(vec3(k - height(pos + vec2(0.1, 0.0), TIME), 0.1, + k - height(pos + vec2(0.0, 0.1), TIME))); -We need to compute ``NORMAL`` manually because in the next section we will be -using math to create complex-looking waves. +This computes the value for the vertex normal by estimating the height gradients +in the **x** and **z** directions at that point. -Now, we are going to make the ``height()`` function a little more complicated by -offsetting ``position`` by the cosine of ``TIME``. +We will also remove the code assigning to ``NORMAL_MAP`` in ``fragment()``. -.. code-block:: glsl +.. image:: img/normals.webp - float height(vec2 position, float time) { - vec2 offset = 0.01 * cos(position + time); - return texture(noise, (position / 10.0) - offset).x; - } +As these are estimates, we have lost some quality. We can partially address this +by reducing the detail in our noise texture. Open **Mesh > Material > Shader +parameters** and then the :ref:`Noise ` +texture. Set its :ref:`Noise > Frequency ` +value to ``0.005``. -This results in waves that move slowly, but not in a very natural way. The next -section will dig deeper into using shaders to create more complex effects, in -this case realistic waves, by adding a few more mathematical functions. +.. image:: img/set-frequency.webp -Advanced effects: waves ------------------------ +.. image:: img/frequency.webp + +Wave Functions +~~~~~~~~~~~~~~ What makes shaders so powerful is that you can achieve complex effects by using math. To illustrate this, we are going to take our waves to the next level by @@ -298,7 +337,7 @@ We can now replace the contents of our ``height()`` function with ``wave()``. Using this, you get: -.. image:: img/wave1.png +.. image:: img/wave1.webp The shape of the sin wave is too obvious. So let's spread the waves out a bit. We do this by scaling ``position``. @@ -310,9 +349,13 @@ We do this by scaling ``position``. return h; } -Now it looks much better. +.. image:: img/wave2.webp + +This wave has a more natural shape, but it is a bit smooth. In our material settings +open the **Shader Parameters > Noise** texture. Set the :ref:`Noise > Fractal > Octave` +property to ``7``. This gives more height detail. -.. image:: img/wave2.png +.. image:: img/octave.webp We can do even better if we layer multiple waves on top of each other at varying frequencies and amplitudes. What this means is that we are going to scale @@ -341,10 +384,52 @@ keeps the wave in the 0-1 range. With this code you should end up with more complex looking waves and all you had to do was add a bit of math! -.. image:: img/wave3.png +.. image:: img/wave3.webp + +Final Code +---------- + +Here is the code to produce the final effect in the tutorial. The example uses +the same mesh and noise settings as mentioned above. + +.. code-block:: glsl + + shader_type spatial; + + uniform sampler2D noise; + + float wave(vec2 position){ + position += texture(noise, position / 10.0).x * 2.0 - 1.0; + vec2 wv = 1.0 - abs(sin(position)); + return pow(1.0 - pow(wv.x * wv.y, 0.65), 4.0); + } + + float height(vec2 position, float time) { + float d = wave((position + time) * 0.4) * 0.3; + d += wave((position - time) * 0.3) * 0.3; + d += wave((position + time) * 0.5) * 0.2; + d += wave((position - time) * 0.6) * 0.2; + return d; + } + + void vertex() { + vec2 pos = VERTEX.xz; + float k = height(pos, TIME); + VERTEX.y = k; + float offset = 0.1; + NORMAL = normalize(vec3(k - height(pos + vec2(offset, 0.0), TIME), offset, + k - height(pos + vec2(0.0, offset), TIME))); + } + + void fragment() { + float fresnel = sqrt(1.0 - dot(NORMAL, VIEW)); + RIM = 0.2; + METALLIC = 0.0; + ROUGHNESS = 0.01 * (1.0 - fresnel); + ALBEDO = vec3(0.01, 0.03, 0.05) + (0.1 * fresnel); + } -For more information about Spatial shaders read the :ref:`Shading Language -` doc and the :ref:`Spatial Shaders ` -doc. Also look at more advanced tutorials in the :ref:`Shading section -` and the :ref:`3D ` -sections. +For more information about Spatial shaders read the :ref:`Shading Language ` +and :ref:`Spatial Shaders ` docs. +Also look at more advanced tutorials in the :ref:`Shading section` +and :ref:`3D ` sections. \ No newline at end of file