Spec-Zone.ru › Qt 6.0

Тип QML Effect

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

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

Object3D

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

Свойства

  • passes : список

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

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

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

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

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

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

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

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

Примечание: Эффекты пост-обработки в настоящее время доступны только в том случае, если режим рендеринга 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 Qt Quick item layers. Установка свойства 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. Координаты UV из четырехугольной области содержатся в INPUT_UV. Эти значения UV всегда подходят для выборки из INPUT, независимо от используемого API графики во время выполнения (и, следовательно, независимо от направления оси Y на изображениях, поскольку Qt Quick 3D автоматически применяет необходимые корректировки). Обращение к текстуре с внешним изображением выполняется с помощью TEXTURE_UV. INPUT_UV не подходит для кросс-платформенных приложений, поскольку V необходимо перевернуть, чтобы учесть различия в системах координат, упомянутые ранее, используя логику, отличную для текстур, основанных на изображениях, и текстур, используемых в качестве целевых ресурсов рендеринга. К счастью, все это выполняется движком, поэтому в шейдере нет необходимости в дополнительной логике.

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

environment: SceneEnvironment {
    effects: [ simpleEffect ]
}

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

Примечание: Значение свойства shader в 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);.

Для передачи данных между вершинным и фрагментным шейдерами используйте ключевое слово 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);
}

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

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

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

Special keywords in effect shaders

  • 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, подходящие для выборки текстуры с содержимым, загруженным из файла изображения.
  • 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. Это указывает, что текстура постоянно связана с проходом эффекта и не будет повторно использоваться для других целей. Содержимое таких буферов цвета сохраняется между кадрами. Это обычно используется по принципу «пинг-понг» в эффектах, таких как размытие движения: первый проход берёт постоянный буфер в качестве входных данных, помимо основной входной текстуры эффекта, выводя результат в другой промежуточный буфер, в то время как второй проход выводит результат в постоянный буфер. Таким образом, в первом кадре первый проход сэмплирует пустую (прозрачную) текстуру, а в последующих кадрах — результат второго прохода из предыдущего кадра. Третий проход может затем смешать входные данные эффекта и результат второго прохода.

Тип команды 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, рендеринг сцены в текстуру, а затем использование её в качестве текстуры квадрика — не дешёвая операция, особенно на устройствах с низким уровнем железа и ограниченной мощностью обработки фрагментов. Требуемое количество дополнительной графической памяти, а также увеличение нагрузки на GPU зависят от размера View3D (который на встраиваемых устройствах без системы окон часто может быть таким же большим, как разрешение экрана). Многопроходные эффекты, а также применение нескольких эффектов ещё больше увеличивают требования к ресурсам и производительности.

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

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

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

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

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

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

passes : list

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

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

Spec-Zone.ru

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