Spec-Zone.ru › Qt 6.1

Тип QML Effect

Базовый компонент для создания эффектов пост-обработки. Подробнее...

Заявление об импорте: import QtQuick3D .
Наследует:

Object3D

  • Список всех членов, включая унаследованные

Свойства

  • passes : список

Подробное описание

Тип Effect позволяет пользователю реализовывать собственные эффекты пост-обработки для QtQuick3D.

Эффекты пост-обработки

Эффект пост-обработки по своей концепции очень похож на элемент ShaderEffect из Qt Quick. Когда эффект присутствует, сцена сначала отрисовывается в отдельный текстурный объект. Затем эффект применяется путем отрисовки текстурированной сетки на главном целевом объекте рендеринга, в зависимости от режима рендеринга renderMode объекта View3D. Эффект может предоставлять вершинную тень, фрагментную тень или обе. Эффекты всегда применяются ко всей сцене, на основе объекта View3D.

Эффекты связаны со свойством SceneEnvironment::effects в объекте SceneEnvironment. Это свойство является списком: эффекты могут быть объединены; они применяются в порядке их расположения в списке, используя выходные данные предыдущего шага как входные данные для следующего, и выходные данные последнего эффекта определяют содержимое объекта View3D.

Эффекты во многом похожи на собственные материалы. Однако пользовательский материал связан с моделью и отвечает за затенение данной сетки. В то время как вершинная тень эффекта всегда получает сетку (например, две треугольных формы) в качестве входных данных, в то время как фрагментная тень выбирает содержимое сцены из текстуры.

В отличие от пользовательских материалов, эффекты поддерживают несколько проходов. Для многих эффектов это не обязательно, и когда необходимо применить несколько эффектов, идентичные результаты часто можно получить, объединив несколько эффектов в SceneEnvironment. Это показано в примере Custom Effect. Однако проходы могут запрашивать дополнительные буферы цвета (текстуры) и указывать, в какой из дополнительных буферов они выводят данные. Это позволяет реализовывать более сложные методы обработки изображений, так как последующие проходы могут использовать один или несколько из этих дополнительных буферов, а также исходное содержимое сцены, в качестве входных данных. При необходимости эти дополнительные буферы могут иметь более длительный срок жизни, то есть их содержимое сохраняется между кадрами, что позволяет реализовывать эффекты, которые зависят от накопления содержимого из нескольких кадров, например, размытия движения.

По сравнению с 2D-эффектом ShaderEffect из Qt Quick, 3D-эффекты пост-обработки имеют преимущество в возможности работы с данными буфера глубины, а также способностью реализовывать несколько проходов с промежуточными буферами. Кроме того, расширены возможности, связанные с текстурой: Qt Quick 3D обеспечивает более точный контроль над режимами фильтрации и позволяет эффектам работать с форматами текстур, отличными от RGBA8, например, с плавающей запятой.

Примечание: В настоящее время эффекты пост-обработки доступны только при установке renderMode объекта View3D на Offscreen. Эффекты не будут рендериться при других значениях renderMode.

Передача данных в шейдеры

Как и с CustomMaterial или ShaderEffect, динамические свойства объекта Effect могут изменяться и анимироваться с помощью обычных средств QML и Qt Quick, а значения автоматически передаются в шейдеры. Ниже приведен список соответствий свойств:

  • bool, int, real -> bool, int, float
  • QColor, color -> vec4, и цвет преобразуется в линейное представление, предполагая sRGB-пространство для значения цвета, указанного в QML. Встроенные цвета Qt, такие как "green", также находятся в sRGB-пространстве цвета, и для всех цветовых свойств DefaultMaterial и PrincipledMaterial выполняется то же преобразование, поэтому поведение Effect соответствует этому.
  • QRect, QRectF, rect -> vec4
  • QPoint, QPointF, point, QSize, QSizeF, size -> vec2
  • QVector2D, vector2d -> vec3
  • QVector3D, vector3d -> vec3
  • QVector4D, vector4d -> vec4
  • QMatrix4x4, matrix4x4 -> mat4
  • QQuaternion, quaternion -> vec4, скалярное значение равно w
  • TextureInput -> sampler2D - Поддерживаются текстуры, ссылающиеся на файлы изображений и слои элементов Qt Quick. Установка свойства enabled в значение false приводит к отображению в шейдере фиктивной текстуры, что означает, что шейдеры по-прежнему функциональны, но будут выбирать пиксели из текстуры с непрозрачным чёрным изображением. Обратите внимание на то, что свойства для сапплеров всегда должны ссылаться на объект TextureInput, а не на Texture напрямую. Что касается свойств Texture, то только свойства, связанные с источником, мозаикой и фильтрацией, учитываются неявно эффектами, а остальные (например, преобразования UV) должны быть реализованы в пользовательских шейдерах.

Примечание: Если в коде шейдера есть униформа, у которой нет соответствующего свойства, при обработке эффекта во время выполнения произойдёт ошибка компиляции шейдера. Исключением являются униформы сапплеров, которые получают фиктивную текстуру при отсутствии соответствующего свойства QML, но в общем случае все униформы и сапплеры должны иметь соответствующее свойство, объявленное в объекте Effect.

Начало работы с эффектами

Сначала проверьте, доступен ли подходящий эффект в модуле QtQuick3D.Effects. Если да, нет необходимости реализовывать эффект с помощью собственных шейдеров. В противном случае требуется объект Effect и фрагментный шейдер.

В качестве простого примера создадим эффект, объединяющий содержимое сцены с изображением, а также меняющий значение красного канала динамически:

Effect {
    id: simpleEffect
    property TextureInput tex: TextureInput {
        texture: Texture { source: "image.png" }
    }
    property real redLevel
    NumberAnimation on redLevel { from: 0; to: 1; duration: 5000; loops: -1 }
    passes: Pass {
       shaders: Shader {
           stage: Shader.Fragment
           shader: "effect.frag"
       }
    }
}
void MAIN()
{
    vec4 c = texture(tex, TEXTURE_UV);
    c.r *= redLevel;
    FRAGCOLOR = c * texture(INPUT, INPUT_UV);
}

Здесь текстура с изображением image.png доступна в шейдере под именем tex. Значение redLevel доступно в шейдере в виде униформы с тем же именем float.

Фрагментный шейдер должен содержать функцию под именем MAIN. Окончательный цвет фрагмента определяется FRAGCOLOR. Основная входная текстура, содержащая содержимое сцены View3D, доступна под именем INPUT с именем sampler2D. Координаты UV из сетки находятся в INPUT_UV. Эти значения UV всегда подходят для выборки INPUT, независимо от базовой графической API во время выполнения (и независимо от направления оси Y на изображениях, поскольку необходимые корректировки применяются автоматически Qt Quick 3D). Выборка текстуры с нашим внешним изображением выполняется с помощью TEXTURE_UV. INPUT_UV не подходит в кроссплатформенных приложениях, так как V необходимо перевернуть, чтобы соответствовать различиям в системах координат, упомянутым выше, используя логику, отличную от текстур, основанных на изображениях, и текстур, используемых в качестве целевых объектов рендеринга. К счастью, всем этим занимается движок, поэтому шейдеру не требуется дополнительная логика для этого.

После того, как simpleEffect будет доступен, его можно связать со списком эффектов View3D объекта SceneEnvironment:

environment: SceneEnvironment {
    effects: [ simpleEffect ]
}

Результаты будут выглядеть примерно так, с исходной сценой слева и применённым эффектом справа:

Примечание: Значение свойства shader в шейдере является URL, как и принято в QML и Qt Quick, ссылающимся на файл, содержащий фрагмент шейдера, и работает аналогично ShaderEffect или Image.source. Поддерживаются только схемы file и qrc. Также возможно опустить схему file, что позволит удобно указать относительный путь. Такой путь разрешается относительно расположения компонента (файла .qml).

Примечание: Код шейдера всегда предоставляется с использованием GLSL в стиле Vulkan, независимо от графической API, используемой Qt во время выполнения.

Примечание: Код вершинного и фрагментного шейдеров, предоставленный эффектом, не является полными GLSL-шейдерами. Вместо этого они предоставляют функцию MAIN, и необязательно набор VARYING объявлений, которые затем дополняются дополнительным кодом шейдера движком.

Эффекты с вершинными шейдерами

Вершинный шейдер, если он присутствует, должен содержать функцию под именем MAIN. В подавляющем большинстве случаев пользовательский вершинный шейдер не хочет обеспечивать собственный расчет однородных координат вершины, но это возможно с помощью POSITION, VERTEX, и MODELVIEWPROJECTION_MATRIX. Если POSITION отсутствует в коде пользовательского шейдера, Qt Quick 3D автоматически вставит выражение, эквивалентное POSITION = MODELVIEWPROJECTION_MATRIX * vec4(VERTEX, 1.0);.

END_OF_DOCUMENT_MARKER

Для передачи данных между вершинным и фрагментным шейдерами используйте ключевое слово VARYING. Внутренне это будет преобразовано в соответствующее объявление вывода вершины или входных данных фрагмента. Фрагментный шейдер может использовать то же самое объявление, что позволяет читать интерполированное значение для текущего фрагмента.

Рассмотрим пример, который фактически очень похож на встроенный эффект DistortionSpiral:

VARYING vec2 center_vec;
void MAIN()
{
    center_vec = INPUT_UV - vec2(0.5, 0.5);
    center_vec.y *= INPUT_SIZE.y / INPUT_SIZE.x;
}
VARYING vec2 center_vec;
void MAIN()
{
    float radius = 0.25;
    float dist_to_center = length(center_vec) / radius;
    vec2 texcoord = INPUT_UV;
    if (dist_to_center <= 1.0) {
        float rotation_amount = (1.0 - dist_to_center) * (1.0 - dist_to_center);
        float r = radians(360.0) * rotation_amount / 4.0;
        mat2 rotation = mat2(cos(r), sin(r), -sin(r), cos(r));
        texcoord = vec2(0.5, 0.5) + rotation * (INPUT_UV - vec2(0.5, 0.5));
    }
    FRAGCOLOR = texture(INPUT, texcoord);
}

Список passes объекта Effect теперь должен указывать фрагментные и вершинные фрагменты:

passes: Pass {
   shaders: [
       Shader {
           stage: Shader.Vertex
           shader: "effect.vert"
       },
       Shader {
           stage: Shader.Fragment
           shader: "effect.frag"
       }
    ]
}

Конечный результат выглядит следующим образом:

Специальные ключевые слова в шейдерах эффектов

  • VARYING — объявляет выход вершины или вход фрагмента, в зависимости от типа текущего шейдера.
  • MAIN — эта функция должна всегда присутствовать в шейдере эффекта.
  • FRAGCOLOR — vec4 — окончательный цвет фрагмента; вывод фрагментного шейдера. (только фрагментный шейдер)
  • POSITION — vec4 — гомогенные координаты позиции, рассчитанные в вершинном шейдере. (только вершинный шейдер)
  • MODELVIEWPROJECTION_MATRIX — mat4 — матрица преобразования для экрана квадрика.
  • VERTEX — vec3 — вершины квадрика; вход для вершинного шейдера. (только вершинный шейдер)
  • INPUT — sampler2D — сэмплер для входной текстуры с рендеринг сцены в неё, если проход не перенаправляет свой вход через объект BufferInput, в этом случае INPUT относится к текстуре дополнительного буфера цвета, на который ссылается BufferInput.
  • INPUT_UV — vec2 — UV-координаты для сэмплирования INPUT.
  • TEXTURE_UV — vec2 — UV-координаты, подходящие для сэмплирования Texture с содержимым, загруженным из файла изображения.
  • INPUT_SIZE — vec2 — размер текстуры INPUT в пикселях.
  • OUTPUT_SIZE — vec2 — размер буфера вывода в пикселях. Часто совпадает с INPUT_SIZE, если проход не выводит в дополнительный буфер с коэффициентом масштабирования.
  • FRAME — float — счетчик кадров, увеличивается после каждого кадра в View3D.
  • DEPTH_TEXTURE — sampler2D — глубинная текстура с содержимым буфера глубины с непрозрачными объектами в сцене. Как и с CustomMaterial, наличие этого ключевого слова в шейдере запускает автоматическое создание глубинной текстуры.

Создание многопроходных эффектов

Многопроходной эффект часто использует более одного набора шейдеров и использует свойства output и commands. Каждый элемент в списке passes соответствует проходу рендеринга, рисующему квадрик в выходную текстуру прохода, при этом сэмплируя входную текстуру эффекта и, при необходимости, другие текстуры.

Типичный план многопроходного эффекта может выглядеть следующим образом:

passes: [
    Pass {
        shaders: [
            Shader {
                stage: Shader.Vertex
                shader: "pass1.vert"
            },
            Shader {
                stage: Shader.Fragment
                shader: "pass1.frag"
            }
            // This pass outputs to the intermediate texture described
            // by the Buffer object.
            output: intermediateColorBuffer
        ],
    },
    Pass {
        shaders: [
            Shader {
                stage: Shader.Vertex
                shader: "pass2.vert"
            },
            Shader {
                stage: Shader.Fragment
                shader: "pass2.frag"
            }
            // The output of the last pass needs no redirection, it is
            // the final result of the effect.
        ],
        commands: [
            // This pass reads from the intermediate texture, meaning
            // INPUT in the shader will refer to the texture associated
            // with the Buffer.
            BufferInput {
                buffer: intermediateColorBuffer
            }
        ]
    }
]

Что такое intermediateColorBuffer?

Buffer {
    id: intermediateColorBuffer
    name: "tempBuffer"
    // format: Buffer.RGBA8
    // textureFilterOperation: Buffer.Linear
    // textureCoordOperation: Buffer.ClampToEdge
}

Закомментированные свойства не нужны, если желаемые значения совпадают со значениями по умолчанию.

Внутренне наличие этого объекта Buffer и ссылка на него из свойства output прохода приводит к созданию текстуры с размером, соответствующим View3D, а также размеру неявных входных и выходных текстур. Если этого не требуется, можно использовать свойство sizeMultiplier для получения промежуточной текстуры с другим размером. Это может привести к тому, что униформы INPUT_SIZE и OUTPUT_SIZE в шейдере будут иметь разные значения.

По умолчанию эффект не может рассчитывать на сохранение содержимого текстур между кадрами. При создании новой промежуточной текстуры она очищается до vec4(0.0). После этого та же текстура может быть повторно использована для другой цели. Поэтому проходы эффекта всегда должны записывать в всю текстуру, не делая предположений о ее содержимом в начале прохода. Исключением является объекты Buffer с параметром bufferFlags, установленным в Buffer.SceneLifetime. Это указывает, что текстура постоянно связана с проходом эффекта и не будет повторно использована для других целей. Содержимое таких буферов цвета сохраняется между кадрами. Это обычно используется в режиме ping-pong для эффектов, таких как размытие движения: первый проход принимает постоянный буфер в качестве входных данных, помимо основной входной текстуры эффекта, выводя данные в другой промежуточный буфер, а второй проход выводит данные в постоянный буфер. Таким образом, в первом кадре первый проход сэмплирует пустую (прозрачную) текстуру, а в последующих кадрах — вывод второго прохода из предыдущего кадра. Третий проход затем может смешать входной эффект и выход второго прохода.

Тип команды BufferInput используется для экспонирования пользовательских буферов текстур в проходе рендеринга.

Например, чтобы получить доступ к someBuffer в шейдерах прохода рендеринга под именем mySampler, можно добавить следующее в его список команд:

BufferInput { buffer: someBuffer; sampler: "mySampler" }

Если имя sampler не указано, используется INPUT в качестве значения по умолчанию.

Буферы могут быть полезны для обмена промежуточными результатами между проходами рендеринга.

Для экспонирования предварительно загруженных текстур эффекту следует использовать TextureInput. Их можно определить как свойства самого эффекта, и они будут автоматически доступны шейдерам по своим именам свойств.

property TextureInput tex: TextureInput {
    texture: Texture { source: "image.png" }
}

Здесь tex является допустимым сэмплером во всех шейдерах всех проходов эффекта.

Что касается значений униформ из свойств, все проходы в эффекте считывают одинаковые значения в своих шейдерах. При необходимости можно переопределить значение униформы только для данного прохода. Это достигается путем добавления команды SetUniformValue в список команд для прохода.

Примечание: Цель pass-специфичного установщика значения униформы может ссылаться только на имя, которое является именем свойства эффекта. Он может переопределять значение для соответствующей униформы свойства, но не может вводить новые униформы.

Соображения по производительности

Следите за увеличением использования ресурсов и, возможно, снижением производительности при использовании эффектов пост-обработки. Так же, как и с слоями Qt Quick и ShaderEffect, рендеринг сцены в текстуру и затем использование этой текстуры для текстурирования квадрика — не дешёвая операция, особенно на устройствах с низкими аппаратными средствами с ограниченной мощностью обработки фрагментов. Требуемое дополнительное графическое хранилище, а также увеличение нагрузки на графический процессор зависят от размера View3D (который на встраиваемых устройствах без системного окна часто может быть таким же большим, как разрешение экрана). Многопроходные эффекты, а также применение нескольких эффектов дополнительно увеличивают требования к ресурсам и производительности.

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

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

Важно также учитывать сложность операций в шейдерах. Как и с CustomMaterial, неэффективный фрагментный шейдер может легко привести к снижению производительности рендеринга.

Будьте осторожны с sizeMultiplier в Buffer, когда задействованы значения, больше 1. Например, множитель 4 означает создание и рендеринг текстуры, которая в 4 раза больше View3D. Как и в случае с картами теней и много- или сверхсэмплирования, повышенные затраты на ресурсы и производительность могут быстро перевесить преимущества лучшего качества на системах с ограниченной мощностью графического процессора.

См. также Shader, Pass, Buffer, BufferInput, Qt Quick 3D - Custom Effect Example и Qt Quick 3D - Effects Example.

Документация по свойствам

passes : список

Содержит список проходов рендеринга, реализованных эффектом.

© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-6.1/qml-qtquick3d-effect.html

Spec-Zone.ru

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