your_second_spatial_shader.rst 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. .. _doc_your_second_spatial_shader:
  2. Your first Spatial shader: part 2
  3. =================================
  4. From a high-level, what Godot does is give the user a bunch of parameters that can be optionally set
  5. (``AO``, ``SSS_Strength``, ``RIM``, etc.). These parameters correspond to different complex effects
  6. (Ambient Occlusion, SubSurface Scattering, Rim Lighting, etc.). When not written to, the code is thrown
  7. out before it is compiled and so the shader does not incur the cost of the extra feature. This makes it
  8. easy for users to have complex PBR-correct shading, without writing complex shaders. Of course, Godot
  9. also allows you to ignore all these parameters and write a fully customized shader.
  10. For a full list of these parameters see the :ref:`spatial shader <doc_spatial_shader>` reference doc.
  11. A difference between the vertex function and a fragment function is that the vertex function
  12. runs per vertex and sets properties such as ``VERTEX`` (position) and ``NORMAL``, while
  13. the fragment shader runs per pixel and, most importantly, sets the ``ALBEDO`` color of the :ref:`Mesh<class_MeshInstance>`.
  14. Your first spatial fragment function
  15. ------------------------------------
  16. As mentioned in the previous part of this tutorial. The standard use of the fragment function
  17. in Godot is to set up different material properties and let Godot handle the rest. In order
  18. to provide even more flexibility, Godot also provides things called render modes. Render
  19. modes are set at the top of the shader, directly below ``shader_type``, and they specify
  20. what sort of functionality you want the built-in aspects of the shader to have.
  21. For example, if you do not want to have lights affect an object, set the render mode to
  22. ``unshaded``:
  23. .. code-block:: glsl
  24. render_mode unshaded;
  25. You can also stack multiple render modes together. For example, if you want to use toon
  26. shading instead of more-realistic PBR shading, set the diffuse mode and specular mode to toon:
  27. .. code-block:: glsl
  28. render_mode diffuse_toon, specular_toon;
  29. This model of built-in functionality allows you to write complex custom shaders by changing
  30. only a few parameters.
  31. For a full list of render modes see the :ref:`Spatial shader reference <doc_spatial_shader>`.
  32. In this part of the tutorial, we will walk through how to take the bumpy terrain from the
  33. previous part and turn it into an ocean.
  34. First let's set the color of the water. We do that by setting ``ALBEDO``.
  35. ``ALBEDO`` is a ``vec3`` that contains the color of the object.
  36. Let's set it to a nice shade of blue.
  37. .. code-block:: glsl
  38. void fragment() {
  39. ALBEDO = vec3(0.1, 0.3, 0.5);
  40. }
  41. .. image:: img/albedo.png
  42. We set it to a very dark shade of blue because most of the blueness of the water will
  43. come from reflections from the sky.
  44. The PBR model that Godot uses relies on two main parameters: ``METALLIC`` and ``ROUGHNESS``.
  45. ``ROUGHNESS`` specifies how smooth/rough the surface of a material is. A low ``ROUGHNESS`` will
  46. make a material appear like a shiny plastic, while a high roughness makes the material appear
  47. more solid in color.
  48. ``METALLIC`` specifies how much like a metal the object is. It is better set close to ``0`` or ``1``.
  49. Think of ``METALLIC`` as changing the balance between the reflection and the ``ALBEDO`` color. A
  50. high ``METALLIC`` almost ignores ``ALBEDO`` altogether, and looks like a mirror of the sky. While
  51. a low ``METALLIC`` has a more equal representation of sky color and ``ALBEDO`` color.
  52. ``ROUGHNESS`` increases from ``0`` to ``1`` from left to right while ``METALLIC`` increase from
  53. ``0`` to ``1`` from top to bottom.
  54. .. image:: img/PBR.png
  55. .. note:: ``METALLIC`` should be close to ``0`` or ``1`` for proper PBR shading. Only set it between
  56. them for blending between materials.
  57. Water is not a metal, so we will set its ``METALLIC`` property to ``0.0``. Water is also highly
  58. reflective, so we will set its ``ROUGHNESS`` property to be quite low as well.
  59. .. code-block:: glsl
  60. void fragment() {
  61. METALLIC = 0.0;
  62. ROUGHNESS = 0.01;
  63. ALBEDO = vec3(0.1, 0.3, 0.5);
  64. }
  65. .. image:: img/plastic.png
  66. Now we have a smooth plastic looking surface. It is time to think about some particular properties of
  67. water that we want to emulate. There are two main ones that will take this from a weird plastic surface
  68. to nice stylized water. The first is specular reflections. Specular reflections are those bright spots
  69. you see from where the sun reflects directly into your eye. The second is fresnel reflectance.
  70. Fresnel reflectance is the property of objects to become more reflective at shallow angles. It is the
  71. reason why you can see into water below you, but farther away it reflects the sky.
  72. In order to increase the specular reflections, we will do two things. First, we will change the render
  73. mode for specular to toon because the toon render mode has larger specular highlights.
  74. .. code-block:: glsl
  75. render_mode specular_toon;
  76. .. image:: img/specular-toon.png
  77. Second we will
  78. add rim lighting. Rim lighting increases the effect of light at glancing angles. Usually it is used
  79. to emulate the way light passes through fabric on the edges of an object, but we will use it here to
  80. help achieve a nice watery effect.
  81. .. code-block:: glsl
  82. void fragment() {
  83. RIM = 0.2;
  84. METALLIC = 0.0;
  85. ROUGHNESS = 0.01;
  86. ALBEDO = vec3(0.1, 0.3, 0.5);
  87. }
  88. .. image:: img/rim.png
  89. In order to add fresnal reflectance we will compute a fresnel term in our fragment shader.
  90. We are not going to use a real fresnel term, instead we will approximate it using the dot
  91. product of the ``NORMAL`` and ``VIEW`` vectors. The ``NORMAL`` vector points away from a
  92. surface of the, while the ``VIEW`` vector is the direction between your eye and that point
  93. on the surface. The dot product between them is a handy way to tell when you are looking
  94. at the surface head-on your at a glancing angle.
  95. .. code-block:: glsl
  96. float fresnel = sqrt(1.0 - dot(NORMAL, VIEW));
  97. And mix it into both ``ROUGHNESS`` and ``ALBEDO``. This is the benefit of ShaderMaterials over
  98. SpatialMaterials. With SpatialMaterials we could set these properties with a texture, or to a flat
  99. number. But with shaders we can set them based on any mathematical function that we can dream up.
  100. .. code-block:: glsl
  101. void fragment() {
  102. float fresnel = sqrt(1.0 - dot(NORMAL, VIEW));
  103. RIM = 0.2;
  104. METALLIC = 0.0;
  105. ROUGHNESS = 0.01 * (1.0 - fresnel);
  106. ALBEDO = vec3(0.1, 0.3, 0.5) + (0.1 * fresnel);
  107. }
  108. .. image:: img/fresnel.png
  109. And now, with only 5 lines of code, you can have complex looking water. Now that we have
  110. lighting, this water is looking too bright. Let's darken it. This is done easily by
  111. decreasing the values of the ``vec3`` we pass into ``ALBEDO``. Let's set them to
  112. ``vec3(0.01, 0.03, 0.05)``.
  113. .. image:: img/dark-water.png
  114. Animating with ``TIME``
  115. -----------------------
  116. Going back to the vertex function, we can animated the waves using the built-in variable ``TIME``.
  117. ``TIME`` is a built-in variable that is accessible from the vertex and fragment functions.
  118. In the last tutorial we calculated height by reading from a heightmap. For this tutorial,
  119. we will do the same. Put the heightmap code in a function called ``height()``.
  120. .. code-block:: glsl
  121. float height(vec2 position) {
  122. return texture(noise, position / 10.0).x; //scaling factor is based on mesh size (This PlanMesh is 10x10)
  123. }
  124. In order to use ``TIME`` in the ``height()`` function we need to pass it in.
  125. .. code-block:: glsl
  126. float height(vec2 position, float time) {
  127. }
  128. And make sure to correctly pass it in inside the vertex function.
  129. .. code-block:: glsl
  130. void vertex() {
  131. vec2 pos = VERTEX.xz;
  132. float k = height(pos, TIME);
  133. VERTEX.y = k;
  134. }
  135. Instead of using a normalmap to calculate normals. We are going to compute them manually in the
  136. ``vertex()`` function. To do so use the following line of code.
  137. .. code-block:: glsl
  138. NORMAL = normalize(vec3(k - height(pos + vec2(0.1, 0.0), TIME), 0.1, k - height(pos + vec2(0.0, 0.1), TIME)));
  139. We need to compute ``NORMAL`` manually because in the next section we will be using math to create
  140. complex-looking waves.
  141. Now, we are going to make the ``height()`` function a little more complicated by offsetting ``position``
  142. by the cosine of ``TIME``.
  143. .. code-block:: glsl
  144. float height(vec2 position, float time) {
  145. vec2 offset = 0.01 * cos(position + time);
  146. return texture(noise, (position / 10.0) - offset).x;
  147. }
  148. This results in waves that move slowly, but not in a very natural way. The next section will dig deeper
  149. into using shaders to create more complex effects, in this case realistic waves, by adding a few
  150. more mathematical functions.
  151. Advanced effects: waves
  152. -----------------------
  153. What makes shaders so powerful is that you can achieve complex effects by using math. To illustrate
  154. this, we are going to take our waves to the next level by modifying the ``height()`` function and
  155. by introducing a new function called ``wave()``.
  156. ``wave()`` has one parameter, ``position``, which is the same as it is in ``height()``.
  157. We are going to call ``wave()`` multiple times in ``height()`` in order to fake the way waves look.
  158. .. code-block:: glsl
  159. float wave(vec2 position){
  160. position += texture(noise, position / 10.0).x * 2.0 - 1.0;
  161. vec2 wv = 1.0 - abs(sin(position));
  162. return pow(1.0 - pow(wv.x * wv.y, 0.65), 4.0);
  163. }
  164. At first this looks complicated. So let's go through it line-by-line.
  165. .. code-block:: glsl
  166. position += texture(noise, position / 10.0).x * 2.0 - 1.0;
  167. Offset the position by the ``noise`` texture. This will make the waves curve so they are not straight lines
  168. completely aligned with the grid.
  169. .. code-block:: glsl
  170. vec2 wv = 1.0 - abs(sin(position));
  171. Define a wave-like function using ``sin()`` and ``position``. Normally ``sin()`` waves are very round.
  172. We use ``abs()`` to absolute to give them a sharp ridge and constrain them to the 0-1 range. And then we
  173. subtract it from ``1.0`` to put the peak on top.
  174. .. code-block:: glsl
  175. return pow(1.0 - pow(wv.x * wv.y, 0.65), 4.0);
  176. Multiply the x-directional wave by the y-directional wave and raise it to a power to sharpen the peaks.
  177. Then subtract that from ``1.0`` so that the ridges become peaks and raise that to a power to sharpen the
  178. ridges.
  179. We can now replace the contents of our ``height()`` function with ``wave()``.
  180. .. code-block:: glsl
  181. float height(vec2 position, float time) {
  182. float h = wave(position);
  183. }
  184. Using this you get:
  185. .. image:: img/wave1.png
  186. The shape of the sin wave is too obvious. So let's spread the waves out a bit. We do this by scaling ``position``.
  187. .. code-block:: glsl
  188. float height(vec2 position, float time) {
  189. float h = wave(position*0.4);
  190. }
  191. Now it looks much better.
  192. .. image:: img/wave2.png
  193. We can do even better if we layer multiple waves on top of each other at varying
  194. frequencies and amplitudes. What this means is that we are going to scale position for each one to make
  195. the waves thinner or wider (frequency). And we are going to multiply the output of the wave to make them shorter
  196. or taller (amplitude).
  197. Here is an example for how you could layer the four waves to achieve nicer looking waves.
  198. .. code-block:: glsl
  199. float height(vec2 position, float time) {
  200. float d = wave((position + time) * 0.4, 8.0) * 0.3;
  201. d += wave((position - time) * 0.3, 8.0) * 0.3;
  202. d += wave((position + time) * 0.5, 4.0) * 0.2;
  203. d += wave((position - time) * 0.6, 4.0) * 0.2;
  204. return d;
  205. }
  206. Note that we add time to two and subtract it from the other two. This makes the waves move in different directions
  207. creating a complex effect. Also note that the amplitudes (the number the result is multiplied by) all
  208. add up to ``1.0``. This keeps the wave in the 0-1 range.
  209. With this code you should end up with more complex looking waves and all you had to do was add a little bit
  210. of math!
  211. .. image:: img/wave3.png
  212. For more information about Spatial shaders read the :ref:`Shading Language <doc_shading_language>`
  213. doc and the :ref:`Spatial Shaders <doc_spatial_shader>` doc. Also look at more advanced tutorials
  214. in the :ref:`Shading section <toc-learn-features-shading>` and the :ref:`3D <toc-learn-features-3d>` sections.