your_second_3d_shader.rst 12 KB

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