Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

用粒子控制数千条鱼

MeshInstance3D 的问题在于更新其变换数组的成本很高。它非常适合在场景周围放置许多静态对象。但在场景周围移动对象仍然很困难。

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

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

shader_type 设置为 particles

shader_type particles

然后添加以下两个函数:

float rand_from_seed(in uint seed) {
  int k;
  int s = int(seed);
  if (s == 0)
    s = 305420679;
  k = s / 127773;
  s = 16807 * (s - k * 127773) - 2836 * k;
  if (s < 0)
    s += 2147483647;
  seed = uint(s);
  return float(seed % uint(65536)) / 65535.0;
}

uint hash(uint x) {
  x = ((x >> uint(16)) ^ x) * uint(73244475);
  x = ((x >> uint(16)) ^ x) * uint(73244475);
  x = (x >> uint(16)) ^ x;
  return x;
}

这些函数来自默认的 ParticleProcessMaterial。它们用于从每个粒子的 RANDOM_SEED 生成一个随机数。

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

接下来,设置你的 start() 函数。粒子着色器包含一个 start() 函数和一个 process() 函数。

start() 函式中的代码仅在粒子系统启动时运作。process() 函式中的代码将始终运作。

我们需要生成 4 个随机数:其中 3 个用于创建一个随机位置,1 个用于游泳周期的随机偏移。

首先,使用上面提供的 hash() 函数在 start() 函数内生成 4 个种子:

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

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

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

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

TRANSFORM[3].xyz = position * 20.0;

请记住,到目前为止所有这些代码都位于 start() 函数内部。

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

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

让我们通过在 start() 函数中设置 VELOCITY 来变换鱼。

VELOCITY.z = 10.0;

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

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

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

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

如果你在 process() 函式中设定速度,你也可以让每条鱼随着时间的推移改变其速度。

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

CUSTOM.y = VELOCITY.z * 0.1;

代码产生的效果如图:

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

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