Оптимізація за допомогою MultiMeshes

Для великої кількості екземплярів (тисячі), які потрібно постійно обробляти (і при цьому зберігати певний рівень контролю), рекомендованою оптимізацією є безпосереднє використання серверів.

Коли кількість об'єктів сягає сотень тисяч або мільйонів, жоден з цих підходів вже не є ефективним. Проте, залежно від вимог, можлива ще одна оптимізація.

MultiMeshes

MultiMesh - це єдиний примітив малювання, який може малювати до мільйонів об'єктів за один прохід. Він надзвичайно ефективний, оскільки використовує для цього апаратне забезпечення графічного процесора (у OpenGL ES 2.0 він менш ефективний, оскільки не має апаратної підтримки).

Єдиним недоліком є те, що немає можливості відбраковування окремих екземплярів, ні екранної, ні frustum. Це означає, що мільйони об'єктів будуть малюватися завжди або ніколи, залежно від видимості всього MultiMesh. Для них можна надати власне налаштування видимості, але це завжди буде видимість типу всі-або-нікого.

Якщо об'єкти досить прості (лише пара вершин), це не є великою проблемою, оскільки більшість сучасних графічних процесорів оптимізовано для цього випадку використання. Обхідним шляхом є створення декількох MultiMeshes для різних частин світу.

Також можна виконати певну логіку всередині шейдера вершин(за допомогою вбудованих констант INSTANCE_ID або INSTANCE_CUSTOM). Приклад анімації тисяч об'єктів у MultiMesh наведено у посібнику Анімація тисяч рибок. Інформацію шейдеру можна надавати за допомогою текстур (для цього ідеально підходять десяткові формати Image).

Іншою альтернативою є використання GDNative та C++, що має бути надзвичайно ефективним (можна встановити весь стан для всіх об'єктів, використовуючи лінійну пам'ять через функцію VisualServer.multimesh_set_as_bulk_array()). Таким чином, масив може бути створений у декількох потоках, а потім встановлений за один виклик, що забезпечує високу ефективність використання кешу.

Нарешті, не обов'язково, щоб усі екземпляри MultiMesh були видимими. Кількість видимих екземплярів можна контролювати за допомогою властивості MultiMesh.visible_instance_count. Типовим робочим процесом є виділення максимальної кількості екземплярів, які будуть використовуватися, а потім зміна кількості видимих екземплярів залежно від того, скільки з них потрібно в даний момент.

Multimesh приклад

Ось приклад використання MultiMesh з коду. Мови, відмінні від GDScript, можуть бути ефективнішими для мільйонів об'єктів, але для кількох тисяч GDScript має бути чудовим.

extends MultiMeshInstance


func _ready():
    # Create the multimesh.
    multimesh = MultiMesh.new()
    # Set the format first.
    multimesh.transform_format = MultiMesh.TRANSFORM_3D
    multimesh.color_format = MultiMesh.COLOR_NONE
    multimesh.custom_data_format = MultiMesh.CUSTOM_DATA_NONE
    # 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, Transform(Basis(), Vector3(i * 20, 0, 0)))