Work in progress
The content of this page was not yet updated for Godot
4.6
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.
Оптимизация с использованием мультисеток
Для большого количества экземпляров (тысяч), которые необходимо постоянно обрабатывать (и сохранять определенный уровень контроля), рекомендуемой оптимизацией является using servers directly.
Когда количество объектов достигает сотен тысяч или миллионов, ни один из этих подходов уже неэффективен. Тем не менее, в зависимости от требований, возможен ещё один вариант оптимизации.
MultiMeshes (МультиСетки)
MultiMesh — это единый примитив рисования, способный отрисовывать до миллионов объектов за один раз. Он чрезвычайно эффективен, поскольку использует для этого аппаратное обеспечение графического процессора.
Единственный недостаток заключается в отсутствии возможности отбраковки экрана или усеченной области для отдельных экземпляров. Это означает, что миллионы объектов будут всегда или никогда отрисовываться, в зависимости от видимости всей мультисетки. Можно задать для них собственный прямоугольник видимости, но видимость всегда будет по принципу все или ничего.
Если объекты достаточно простые (всего пара вершин), это, как правило, не представляет особой проблемы, поскольку большинство современных видеокарт оптимизированы для такого использования. Обходной путь — создание нескольких мультисеток для разных областей мира.
Также возможно выполнение некоторой логики внутри вершинного шейдера (используя встроенные константы INSTANCE_ID или INSTANCE_CUSTOM). Пример анимации тысяч объектов в MultiMesh см. в руководстве Animating thousands of fish. Информация для шейдера может быть предоставлена через текстуры (существуют форматы с плавающей точкой Image, которые идеально подходят для этого).
Другой вариант — использовать GDExtension и C++, что должно быть чрезвычайно эффективно (можно установить полное состояние всех объектов, используя линейную память, с помощью функции RenderingServer.multimesh_set_buffer()). Таким образом, массив можно создать в несколько потоков, а затем установить за один вызов, что обеспечивает высокую эффективность кэширования.
Наконец, не обязательно, чтобы все экземпляры MultiMesh были видимыми. Количество видимых экземпляров можно контролировать с помощью свойства MultiMesh.visible_instance_count. Типичный рабочий процесс заключается в выделении максимального количества экземпляров, которые будут использоваться, а затем изменении количества видимых экземпляров в зависимости от текущей потребности.
Пример Multimesh
Вот пример использования MultiMesh из кода. Другие языки, помимо GDScript, могут быть эффективнее для миллионов объектов, но для нескольких тысяч GDScript вполне подойдёт.
extends MultiMeshInstance3D
func _ready():
# Create the multimesh.
multimesh = MultiMesh.new()
# Set the format first.
multimesh.transform_format = MultiMesh.TRANSFORM_3D
# Then resize (otherwise, changing the format is not allowed).
multimesh.instance_count = 10000
# Maybe not all of them should be visible at first.
multimesh.visible_instance_count = 1000
# Set the transform of the instances.
for i in multimesh.visible_instance_count:
multimesh.set_instance_transform(i, Transform3D(Basis(), Vector3(i * 20, 0, 0)))
using Godot;
public partial class MyMultiMeshInstance3D : MultiMeshInstance3D
{
public override void _Ready()
{
// Create the multimesh.
Multimesh = new MultiMesh();
// Set the format first.
Multimesh.TransformFormat = MultiMesh.TransformFormatEnum.Transform3D;
// Then resize (otherwise, changing the format is not allowed)
Multimesh.InstanceCount = 1000;
// Maybe not all of them should be visible at first.
Multimesh.VisibleInstanceCount = 1000;
// Set the transform of the instances.
for (int i = 0; i < Multimesh.VisibleInstanceCount; i++)
{
Multimesh.SetInstanceTransform(i, new Transform3D(Basis.Identity, new Vector3(i * 20, 0, 0)));
}
}
}