用粒子控制数千条鱼

MeshInstance 的问题是,更新转换数组的代价很高。它非常适合在场景周围放置许多静态对象。但在场景中移动物体仍然很困难。

为了使每个实例以有趣的方式移动, 我们将使用一个 Particles 节点.Particles通过在 Shader 中计算和设置每个实例的信息来利用GPU加速.

备注

在 GLES2 中无法使用 Particle,请换用 CPUParticle,它和 Partile 的功能相同,但是不能使用 GPU 加速。

首先创建一个 Particles 节点。然后在“Draw Passes”下将粒子的“Draw Pass 1”设置为你的 Mesh。然后在“Process Material”下创建一个新的 ShaderMaterial

shader_type 设置为 particles

  1. shader_type particles

然后添加以下两个函数:

  1. float rand_from_seed(in uint seed) {
  2. int k;
  3. int s = int(seed);
  4. if (s == 0)
  5. s = 305420679;
  6. k = s / 127773;
  7. s = 16807 * (s - k * 127773) - 2836 * k;
  8. if (s < 0)
  9. s += 2147483647;
  10. seed = uint(s);
  11. return float(seed % uint(65536)) / 65535.0;
  12. }
  13. uint hash(uint x) {
  14. x = ((x >> uint(16)) ^ x) * uint(73244475);
  15. x = ((x >> uint(16)) ^ x) * uint(73244475);
  16. x = (x >> uint(16)) ^ x;
  17. return x;
  18. }

这些函数来自默认的 ParticlesMaterial,可以用来根据每个粒子的 RANDOM_SEED 生成随机数。

粒子着色器的一个独特之处在于, 一些内置的变量可以跨帧保存. TRANSFORM , COLORCUSTOM 都可以在网格的Spatial shader 中访问, 下次运行时也可以在粒子着色器中访问.

接下来,设置您的 vertex 函数。粒子着色器只包含一个顶点函数,不包含其他函数。

首先我们要区分只有在粒子系统启动时才需要运行的代码和应该一直运行的代码. 我们希望在系统第一次运行时, 给每条鱼一个随机的位置和一个随机的动画偏移. 为此, 我们将这段代码包裹在一个 if 语句中, 检查内置变量 RESTART , 当粒子系统重新启动时, 该变量在第一帧变成 true .

从高的级别来看, 这看起来像:

  1. void vertex() {
  2. if (RESTART) {
  3. //Initialization code goes here
  4. } else {
  5. //per-frame code goes here
  6. }
  7. }

接下来, 我们需要生成4个随机数:3个用于创建一个随机位置,1个用于游泳周期的随机偏移量.

首先,使用上面提供的 hash 函数在 RESTART 块中生成 4 个种子:

  1. uint alt_seed1 = hash(NUMBER + uint(1) + RANDOM_SEED);
  2. uint alt_seed2 = hash(NUMBER + uint(27) + RANDOM_SEED);
  3. uint alt_seed3 = hash(NUMBER + uint(43) + RANDOM_SEED);
  4. uint alt_seed4 = hash(NUMBER + uint(111) + RANDOM_SEED);

然后,使用这些种子生成随机数,使用 rand_from_seed

  1. CUSTOM.x = rand_from_seed(alt_seed1);
  2. vec3 position = vec3(rand_from_seed(alt_seed2) * 2.0 - 1.0,
  3. rand_from_seed(alt_seed3) * 2.0 - 1.0,
  4. rand_from_seed(alt_seed4) * 2.0 - 1.0);

最后,将 position 赋值给 TRANSFORM[3].xyz,它是保存位置信息的变换的一部分。

  1. TRANSFORM[3].xyz = position * 20.0;

记住,到目前为止,所有这些代码都位于 RESTART 块中。

网格的顶点着色器, 可以完全复用前一教程中的.

现在每一帧你都可以单独移动每条鱼了,可以直接增加 TRANSFORM 也可以设置 VELOCITY

让我们通过设置鱼的 VELOCITY 来对它们进行变换。

  1. VELOCITY.z = 10.0;

这是设置 VELOCITY 的最基本方法,每个粒子(或鱼)都有相同的速度。

只要设置 VELOCITY,你就可以让鱼自由游动。例如,尝试下面的代码。

  1. VELOCITY.z = cos(TIME + CUSTOM.x * 6.28) * 4.0 + 6.0;

这将为每条鱼在 210 之间设置不同的速度。

如果你在上一个教程中使用了 CUSTOM.y,你也可以基于 VELOCITY 来设置游泳动画的速度。直接用 CUSTOM.y 就好了。

  1. CUSTOM.y = VELOCITY.z * 0.1;

代码产生的效果如图:

../../../_images/scene.gif

使用 ParticlesMaterial 可以随意让鱼的行为变得简单或复杂。在本教程中,我们只设置了速度,但是在你自己的着色器中,你也可以设置 COLOR、旋转、缩放(通过 TRANSFORM)。有关粒子着色器的更多信息,请参阅《粒子着色器参考》