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` 来控制在哪里进行由 `0``1` 的过渡。

```//mask_black and mask_white are uniforms
```

```//wave motion with mask
VERTEX.x += cos(time + body) * mask * wave;
```

```//twist motion with mask
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 MultiMeshes. The first is entirely in editor and is described in the MultiMeshInstance3D tutorial.

```for i in range(\$School.multimesh.instance_count):
var position = Transform3D()
position = position.translated(Vector3(randf() * 100 - 50, randf() * 50 - 25, randf() * 50 - 25))
\$School.multimesh.set_instance_transform(i, position)
```

Running this script will place the fish in random positions in a box around the position of the MultiMeshInstance3D.

If performance is an issue for you, try running the scene with fewer fish.