Work in progress

The content of this page was not yet updated for Godot 4.4 and may be outdated. If you know how to improve this page or you can confirm that it's up to date, feel free to open a pull request.

用粒子控制数千条鱼

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)。有关粒子着色器的更多信息,请参阅《粒子着色器参考》。