Spec-Zone.ru › Qt 6.1

Инкапсулированное рендеринг

Введение

Qt Quick 3D поддерживает инкапсуляцию объектов Model. Инкапсуляция — это техника, при которой один объект рендерится несколько раз с помощью одного вызова отрисовки. (Например, функция OpenGL glDrawElementsInstanced).

Инкапсуляция позволяет дублировать модель с вариациями. В отличие от использования Repeater3D, модель и её графические ресурсы выделяются только один раз. Рендеринг дублированных экземпляров выполняется на низком уровне графическим процессором. В зависимости от сложности модели это может привести к увеличению производительности на несколько порядков.

На практике инкапсуляция выполняется путём определения таблицы, которая указывает, как каждый экземпляр изменяется относительно базовой модели.

Примечание: Функция инкапсуляции находится в стадии технического предварительного просмотра в Qt 6.1 и может быть изменена. Совместимость исходного кода и бинарных файлов может быть нарушена в будущих релизах.

API инкапсуляции

Основной принцип API инкапсуляции заключается в его явности: он не пытается автоматически определять возможности инкапсуляции в рамках существующего API. Вместо этого каждая модель помечается индивидуально путём установки её свойства instancing для ссылки на объект Instancing. Один и тот же объект Instancing может использоваться для нескольких моделей одновременно.

Объект Instancing определяет таблицу, которая определяет, как каждый экземпляр рендерится. Доступные изменения:

  • transformation: положение, вращение и масштабирование
  • color: цвет, который смешивается с материалом модели
  • custom data: данные, которые могут быть использованы пользовательскими материалами

Qt предоставляет два типа QML, которые наследуются от Instancing:

  • InstanceList перечисляет все экземпляры и позволяет привязываться к свойствам каждого экземпляра.
  • RandomInstancing предоставляет способ быстрого тестирования и прототипирования путём генерации случайных экземпляров в заданных границах.

Пример инкапсуляции показывает, как создать сцену с помощью API QML.

Другие виды таблиц экземпляров могут быть определены в C++ путём наследования от QQuick3DInstancing.

Написание пользовательского кода шейдеров позволяет использовать инкапсуляцию для управления дополнительными свойствами, такими как переменные для физически-базируемого рендеринга, веса скелетной анимации, искажения или любые другие свойства, которые могут быть выражены пользовательскими материалами. Пользовательские данные в таблице инкапсуляции состоят из четырёх чисел с плавающей точкой.

Пример пользовательской инкапсуляции демонстрирует, как объединить пользовательские материалы и таблицу экземпляров, реализованную в 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.1/quick3d-instancing.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API