Work in progress

The content of this page was not yet updated for Godot 4.2 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.

用 MultiMeshInstance3D 动画化数以千计条鱼¶

In Godot, this can be accomplished with a custom Shader and a MultiMeshInstance3D. Using the following technique you can render thousands of animated objects, even on low end hardware.

动画化一条鱼¶

The fish model in this tutorial is made by QuaterniusDev and is shared with a creative commons license. CC0 1.0 Universal (CC0 1.0) Public Domain Dedication https://creativecommons.org/publicdomain/zero/1.0/

Typically, you would use bones and a Skeleton3D to animate objects. However, bones are animated on the CPU and so you end having to calculate thousands of operations every frame and it becomes impossible to have thousands of objects. Using vertex animation in a vertex shader, you avoid using bones and can instead calculate the full animation in a few lines of code and completely on the GPU.

1. 从一边运动到另一边

2. 绕着鱼的中心作旋转运动

3. 平移波动运动

4. 平移扭转运动

//time_scale is a uniform float
float time = TIME * time_scale;

//side_to_side is a uniform float
VERTEX.x += cos(time) * side_to_side;

//angle is scaled by 0.1 so that the fish only pivots and doesn't rotate all the way around
//pivot is a uniform float
float pivot_angle = cos(time) * 0.1 * pivot;
mat2 rotation_matrix = mat2(vec2(cos(pivot_angle), -sin(pivot_angle)), vec2(sin(pivot_angle), cos(pivot_angle)));

VERTEX.xz = rotation_matrix * VERTEX.xz;

float body = (VERTEX.z + 1.0) / 2.0; //for a fish centered at (0, 0) with a length of 2

//wave is a uniform float
VERTEX.x += cos(time + body) * wave;

//twist is a uniform float
float twist_angle = cos(time + body) * 0.3 * twist;
mat2 twist_matrix = mat2(vec2(cos(twist_angle), -sin(twist_angle)), vec2(sin(twist_angle), cos(twist_angle)));

VERTEX.xy = twist_matrix * VERTEX.xy;

mask 是个浮点数，从鱼头的 0 过渡到鱼尾的 1 ，我们用 smoothstep 来控制在哪里进行由 01 的过渡。

VERTEX.x += cos(time + body) * mask * wave;

VERTEX.xy = mix(VERTEX.xy, twist_matrix * VERTEX.xy, mask);

制作一群鱼¶

Godot makes it easy to render thousands of the same object using a MultiMeshInstance3D node.

A MultiMeshInstance3D node is created and used the same way you would make a MeshInstance3D node. For this tutorial, we will name the MultiMeshInstance3D node School, because it will contain a school of fish.

MultiMeshes 使用三个额外的实例属性来绘制 Mesh：变换（旋转、平移、缩放）、颜色和自定义。自定义用于使用 Color 传入 4 个多用途变量。

instance_count 指定要绘制的网格的实例数量。现在，将 instance_count 保留为 0，因为当 instance_count 大于 0 时，你不能更改任何其他参数。我们稍后将在 GDScript 中设置 instance_count

transform_format 指定使用的变换是 3D 还是 2D。对于本教程，请选择 3D。

There are two ways to set per-instance transforms for MultiMe