controlling_thousands_of_fish.rst 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. .. _doc_controlling_thousands_of_fish:
  2. Controlling thousands of fish with Particles
  3. ============================================
  4. The problem with :ref:`MeshInstances <class_MeshInstance>` is that it is expensive to
  5. update their transform array. It is great for placing many static objects around the
  6. scene. But it is still difficult to move the objects around the scene.
  7. To make each instance move in an interesting way, we will use a
  8. :ref:`Particles <class_Particles>` node. Particles take advantage of GPU acceleration
  9. by computing and setting the per-instance information in a :ref:`Shader <class_Shader>`.
  10. .. note:: Particles are not available in GLES2, instead use :ref:`CPUParticles <class_CPUParticles>`,
  11. which do the same thing as Particles, but do not benefit from GPU acceleration.
  12. First create a Particles node. Then, under "Draw Passes" set the Particle's "Draw Pass 1" to your
  13. :ref:`Mesh <class_Mesh>`. Then under "Process Material" create a new
  14. :ref:`ShaderMaterial <class_ShaderMaterial>`.
  15. Set the ``shader_type`` to ``particles``.
  16. .. code-block:: glsl
  17. shader_type particles
  18. Then add the following two functions:
  19. .. code-block:: glsl
  20. float rand_from_seed(in uint seed) {
  21. int k;
  22. int s = int(seed);
  23. if (s == 0)
  24. s = 305420679;
  25. k = s / 127773;
  26. s = 16807 * (s - k * 127773) - 2836 * k;
  27. if (s < 0)
  28. s += 2147483647;
  29. seed = uint(s);
  30. return float(seed % uint(65536)) / 65535.0;
  31. }
  32. uint hash(uint x) {
  33. x = ((x >> uint(16)) ^ x) * uint(73244475);
  34. x = ((x >> uint(16)) ^ x) * uint(73244475);
  35. x = (x >> uint(16)) ^ x;
  36. return x;
  37. }
  38. These functions come from the default :ref:`ParticlesMaterial <class_ParticlesMaterial>`.
  39. They are used to generate a random number from each particle's ``RANDOM_SEED``.
  40. A unique thing about particle shaders is that some built-in variables are saved across frames.
  41. ``TRANSFORM``, ``COLOR``, and ``CUSTOM`` can all be accessed in the Spatial shader of the mesh, and
  42. also in the particle shader the next time it is run.
  43. Next, setup your ``vertex`` function. Particles shaders only contain a vertex function
  44. and no others.
  45. First we will distinguish between code that needs to be run only when the particle system starts
  46. and code that should always run. We want to give each fish a random position and a random animation
  47. offset when the system is first run. To do so, we wrap that code in an ``if`` statement that checks the
  48. built-in variable ``RESTART`` which becomes ``true`` for one frame when the particle system is restarted.
  49. From a high level, this looks like:
  50. .. code-block:: glsl
  51. void vertex() {
  52. if (RESTART) {
  53. //Initialization code goes here
  54. } else {
  55. //per-frame code goes here
  56. }
  57. }
  58. Next, we need to generate 4 random numbers: 3 to create a random position and one for the random
  59. offset of the swim cycle.
  60. First, generate 4 seeds inside the ``RESTART`` block using the ``hash`` function provided above:
  61. .. code-block:: glsl
  62. uint alt_seed1 = hash(NUMBER + uint(1) + RANDOM_SEED);
  63. uint alt_seed2 = hash(NUMBER + uint(27) + RANDOM_SEED);
  64. uint alt_seed3 = hash(NUMBER + uint(43) + RANDOM_SEED);
  65. uint alt_seed4 = hash(NUMBER + uint(111) + RANDOM_SEED);
  66. Then, use those seeds to generate random numbers using ``rand_from_seed``:
  67. .. code-block:: glsl
  68. CUSTOM.x = rand_from_seed(alt_seed1);
  69. vec3 position = vec3(rand_from_seed(alt_seed2) * 2.0 - 1.0,
  70. rand_from_seed(alt_seed3) * 2.0 - 1.0,
  71. rand_from_seed(alt_seed4) * 2.0 - 1.0);
  72. Finally, assign ``position`` to ``TRANSFORM[3].xyz``, which is the part of the transform that holds
  73. the position information.
  74. .. code-block:: glsl
  75. TRANSFORM[3].xyz = position * 20.0;
  76. Remember, all this code so far goes inside the ``RESTART`` block.
  77. The vertex shader for your mesh can stay the exact same as it was in the previous tutorial.
  78. Now you can move each fish individually each frame, either by adding to the ``TRANSFORM`` directly
  79. or by writing to ``VELOCITY``.
  80. Let's transform the fish by setting their ``VELOCITY``.
  81. .. code-block:: glsl
  82. VELOCITY.z = 10.0;
  83. This is the most basic way to set ``VELOCITY`` every particle (or fish) will have the same velocity.
  84. Just by setting ``VELOCITY`` you can make the fish swim however you want. For example, try the code
  85. below.
  86. .. code-block:: glsl
  87. VELOCITY.z = cos(TIME + CUSTOM.x * 6.28) * 4.0 + 6.0;
  88. This will give each fish a unique speed between ``2`` and ``10``.
  89. If you used ``CUSTOM.y`` in the last tutorial, you can also set the speed of the swim animation based
  90. on the ``VELOCITY``. Just use ``CUSTOM.y``.
  91. .. code-block:: glsl
  92. CUSTOM.y = VELOCITY.z * 0.1;
  93. This code gives you the following behavior:
  94. .. image:: img/scene.gif
  95. Using a ParticlesMaterial you can make the fish behavior as simple or complex as you like. In this
  96. tutorial we only set Velocity, but in your own Shaders you can also set ``COLOR``, rotation, scale
  97. (through ``TRANSFORM``). Please refer to the :ref:`Particles Shader Reference <doc_particle_shader>`
  98. for more information on particle shaders.