用粒子控制数千条鱼

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

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

注解

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

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

将 “着色器_类型” 设置为 “粒子”.

  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 中访问, 下次运行时也可以在粒子着色器中访问.

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

首先我们要区分只有在粒子系统启动时才需要运行的代码和应该一直运行的代码. 我们希望在系统第一次运行时, 给每条鱼一个随机的位置和一个随机的动画偏移. 为此, 我们将这段代码包裹在一个 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个用于游泳周期的随机偏移量.

首先, 使用上面提供的 “哈希” 函数在 “重新开始” 块中生成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);

然后, 使用这些种子生成随机数, 使用 “随机_自_种子”:

  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);

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

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

记住, 到目前为止, 所有这些代码都位于 “重新开始” 块中.

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

现在你可以单独移动每条鱼的每一帧, 可以通过直接增加 “变换 “, 或是通过编写” 速度”.

让我们通过设置鱼的 “速度” 来改变它们.

  1. VELOCITY.z = 10.0;

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

只要设置 “速度”, 你就可以让鱼自由游动. 例如, 尝试下面的代码.

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

这将给每条鱼一个在 “2” 和 “10” 之间的独特速度.

如果你在上节课中使用 “自定义.y “, 你也可以只使用” 自定义.y “, 根据” 速度”设置游泳动画的速度.

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

代码产生的效果如图:

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

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