Инстанцированное рендерирование
Введение
Qt Quick 3D поддерживает инстанцирование объектов Model. Инстанцирование — это техника, где один объект рендерится несколько раз с помощью одного вызова отрисовки. (Например, функция OpenGL glDrawElementsInstanced.)
Инстанцирование позволяет дублировать модель с вариациями. В отличие от использования Repeater3D, модель и её графические ресурсы выделяются только один раз. Рендеринг дублированных экземпляров выполняется на низком уровне графическим процессором. В зависимости от сложности модели это может дать улучшение производительности на несколько порядков.
На практике инстанцирование выполняется путём определения таблицы, которая указывает, как каждый экземпляр изменяется относительно базовой модели.
API инстанцирования
Основной принцип API инстанцирования заключается в том, что он явный: он не пытается автоматически определять возможности инстанцирования в рамках существующего API. Вместо этого каждая модель помечается индивидуально, установив её свойство instancing для ссылки на объект Instancing. Один и тот же объект Instancing может использоваться для нескольких моделей одновременно.
Объект Instancing определяет таблицу, которая определяет, как каждый экземпляр рендерится. Доступные модификации:
- преобразование: положение, вращение и масштабирование
- цвет: цвет, который смешивается с материалом модели
- пользовательские данные: данные, которые могут использоваться пользовательскими материалами
Qt предоставляет три типа QML, которые наследуются от Instancing:
- InstanceList перечисляет все экземпляры и позволяет привязаться к свойствам каждого экземпляра.
- RandomInstancing предоставляет способ быстрого тестирования и прототипирования путём генерации случайных экземпляров в заданных границах.
- FileInstancing считывает таблицу экземпляров из внешнего файла.
Пример инстанцирования демонстрирует, как создать сцену, используя API QML.
Другие типы таблиц экземпляров могут быть определены в C++ путём наследования от QQuick3DInstancing. Например, система частиц использует свою собственную таблицу инстанцирования внутри. Она доступна как ModelParticle3D.instanceTable.
Написав пользовательский код шейдера, можно использовать инстанцирование для управления дополнительными свойствами, такими как переменные для физически-основанного рендеринга, веса скелетной анимации, искажения или любой другой информации, которая может быть выражена с помощью пользовательских материалов. Пользовательские данные в таблице инстанцирования состоят из четырёх чисел с плавающей запятой.
Пример настраиваемого инстанцирования показывает, как объединить пользовательские материалы и таблицу инстанцирования, реализованную на C++.
Альфа-смешивание и инстанцирование
Для правильного альфа-смешивания необходимо, чтобы полупрозрачные объекты рендерились спереди назад. По этой причине QtQuick3D сортирует непрозрачные и полупрозрачные объекты отдельно и рендерит их в правильном порядке. Однако при инстанцировании графический процессор будет рендерить экземпляры в порядке, заданном таблицей инстанцирования, если сортировка по глубине не включена. По соображениям производительности QtQuick3D по умолчанию не сортирует таблицу, так как это может занять много времени при большом количестве экземпляров. Это означает, что если полупрозрачные экземпляры перекрывают друг друга или другие полупрозрачные объекты, результаты могут выглядеть неправильно. В целом, ошибка менее заметна при низкой непрозрачности.
Полностью непрозрачные объекты вместе с неперекрывающимися полупрозрачными объектами всегда будут рендериться правильно, так как Qt использует проверку буфера глубины, чтобы избежать рисования позади непрозрачных объектов. Однако отсутствие сортировки имеет потенциальные последствия для производительности непрозрачных объектов: они могут не рендериться в оптимальном порядке, что означает, что один и тот же пиксель может быть записан несколько раз, увеличивая работу фрагментного шейдера.
Рендерер не проверяет содержимое таблицы инстанцирования, поэтому её необходимо явно указать, когда таблица инстанцирования содержит полупрозрачные альфа-значения: установите свойство hasTransparency в true чтобы убедиться, что рендерер включает альфа-смешивание. Это относится ко всем экземплярам: даже полностью непрозрачные экземпляры будут рендериться без проверки глубины, что может вызвать видимые ошибки.
Порядок рендеринга относительно остальной части сцены можно настроить, установив смещение глубины модели.
Преобразования и инстанцирование
Каждый экземпляр имеет собственное преобразование в таблице инстанцирования. Это комбинируется с преобразованиями инстанцированной модели. Это немного сложно, так как есть несколько вариантов использования:
- Применение преобразования к модели, которое применяется к каждому отдельному экземпляру. Это позволяет осуществлять быстрые анимации, например, вращая все экземпляры одновременно без изменения таблицы экземпляров.
- Преобразование всей группы экземпляров одновременно.
- Инстанцирование иерархии моделей.
Чтобы поддержать все эти случаи, преобразование модели разделяется на две части: локальное преобразование экземпляра и глобальное преобразование экземпляра. Концептуально инстанцирование выполняется следующим образом:
- Сначала модель преобразуется в соответствии с локальным преобразованием экземпляра.
- Затем каждый экземпляр вычисляется путём применения преобразования из таблицы экземпляров.
- Наконец, вся группа инстанцированных объектов преобразуется в соответствии с глобальным преобразованием экземпляра.
По умолчанию локальное преобразование экземпляра модели состоит из масштаба и вращения модели, а всё остальное попадает в глобальное преобразование экземпляра.
Это можно настроить, установив свойство модели instanceRoot. Это определяет начало системы координат экземпляра. Наиболее распространённое использование — инстанцирование иерархии моделей. Например, сфера, вращающаяся вокруг куба:
Model {
id: cube
instancing: someInstanceTable
source: "#Cube"
materials: DefaultMaterial { diffuseColor: "lightgray" }
Node {
Model {
source: "#Sphere"
instanceRoot: cube
instancing: cube.instancing
x: 150
materials: DefaultMaterial { diffuseColor: "gray" }
}
NumberAnimation on eulerRotation.y {
from: 0
to: 360
duration: 4000
loops: Animation.Infinite
}
}
} Это instanceRoot необходимо, чтобы указать, что экземпляр сферы должен быть размещён так, как будто он является элементом куба. Каждая модель в иерархии всё ещё должна указать свойство instancing: в нормальных случаях они все должны быть установлены на один и тот же объект Instancing.
instanceRoot также может быть использовано при инстанцировании одной модели. Например, цилиндр, вращающийся вокруг точки вне центра:
Node {
id: parentNode
Model {
source: "#Cylinder"
instanceRoot: parentNode
instancing: anotherInstanceTable
x: 25
materials: DefaultMaterial { diffuseColor: "white" }
}
NumberAnimation on eulerRotation.y {
from: 0
to: 360
duration: 1000
loops: Animation.Infinite
}
}
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-6.2/quick3d-instancing.html