Spec-Zone.ru › Qt 5.14

Тип QML ShaderEffect

Применяет пользовательские шейдеры к прямоугольнику. Подробнее...

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

Элемент

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

Свойства

  • blending : bool
  • cullMode : перечисление
  • fragmentShader : строка
  • log : строка
  • mesh : значение
  • status : перечисление
  • supportsAtlasTextures : bool
  • vertexShader : строка

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

Тип ShaderEffect применяет пользовательский шейдер вершин и фрагментов (пикселей) к прямоугольнику. Он позволяет создавать эффекты, такие как тень, размытие, изменение цвета и изгиб страницы, непосредственно в QML.

Примечание: В зависимости от используемого бэкэнда Qt Quick, тип ShaderEffect может не поддерживаться (например, с программным бэкэндом) или использовать другой язык шейдеров с правилами и ожиданиями, отличными от OpenGL и GLSL.

OpenGL и GLSL

Существуют два типа входных данных для vertexShader: переменные и атрибуты. Некоторые из них определены:

  • uniform mat4 qt_Matrix - объединенная матрица преобразования, произведение матриц от корневого элемента до этого ShaderEffect и ортогональной проекции.
  • uniform float qt_Opacity - объединённая непрозрачность, произведение непрозрачностей от корневого элемента до этого ShaderEffect.
  • attribute vec4 qt_Vertex - положение вершины, верхняя левая вершина имеет координаты (0, 0), нижняя правая (ширина, высота).
  • attribute vec2 qt_MultiTexCoord0 - координаты текстуры, верхняя левая координата — (0, 0), нижняя правая (1, 1). Если supportsAtlasTextures имеет значение true, координаты будут основаны на позиции в атласе.

Кроме того, любое свойство, которое можно сопоставить с типом языка шейдеров OpenGL (GLSL), доступно как переменная.

  • bool, int, qreal -> bool, int, float - Если тип в шейдере отличается от типа в QML, значение преобразуется автоматически.
  • QColor -> vec4 - При передаче цветов в шейдер они предварительно умножаются. Таким образом, Qt.rgba(0.2, 0.6, 1.0, 0.5) превращается в vec4(0.1, 0.3, 0.5, 0.5) в шейдере, например.
  • QRect, QRectF -> vec4 - Qt.rect(x, y, w, h) превращается в vec4(x, y, w, h) в шейдере.
  • QPoint, QPointF, QSize, QSizeF -> vec2
  • QVector3D -> vec3
  • QVector4D -> vec4
  • QTransform -> mat3
  • QMatrix4x4 -> mat4
  • QQuaternion -> vec4, скалярное значение — w.
  • Изображение -> sampler2D - Начало в верхнем левом углу, а значения цвета предварительно умножаются. Текстура предоставляется как есть, за исключением fillMode элемента Image. Чтобы включить fillMode, используйте ShaderEffectSource или Image::layer::enabled.
  • ShaderEffectSource -> sampler2D - Начало в верхнем левом углу, а значения цвета предварительно умножаются.

Бэкэнд QML графа сцены может выбрать выделение текстур в атласах текстур. Если текстура, выделенная в атласе, передаётся в ShaderEffect, она по умолчанию копируется из атласа в автономную текстуру, чтобы координаты текстуры охватывали диапазон от 0 до 1, и вы получали ожидаемые режимы обрезки. Однако это увеличит использование памяти. Чтобы избежать копирования текстуры, установите supportsAtlasTextures для простых шейдеров, использующих qt_MultiTexCoord0, или для каждого "uniform sampler2D <имя>", объявите "uniform vec4 qt_SubRect_<имя>", который будет назначен нормализованному прямоугольнику источника текстуры. Для автономных текстур прямоугольник источника — [0, 1]x[0, 1]. Для текстур в атласе прямоугольник источника соответствует части атласа текстур, где хранится текстура. Правильный способ вычисления координат текстуры для текстуры с именем «source» в атласе текстур — «qt_SubRect_source.xy + qt_SubRect_source.zw * qt_MultiTexCoord0».

Вывод из fragmentShader должен быть предварительно умножен. Если blending включён, используется композиция «source-over». Однако аддитивное смешивание можно получить, выведя ноль в альфа-канале.

import QtQuick 2.0

Rectangle {
    width: 200; height: 100
    Row {
        Image { id: img;
                sourceSize { width: 100; height: 100 } source: "qt-logo.png" }
        ShaderEffect {
            width: 100; height: 100
            property variant src: img
            vertexShader: "
                uniform highp mat4 qt_Matrix;
                attribute highp vec4 qt_Vertex;
                attribute highp vec2 qt_MultiTexCoord0;
                varying highp vec2 coord;
                void main() {
                    coord = qt_MultiTexCoord0;
                    gl_Position = qt_Matrix * qt_Vertex;
                }"
            fragmentShader: "
                varying highp vec2 coord;
                uniform sampler2D src;
                uniform lowp float qt_Opacity;
                void main() {
                    lowp vec4 tex = texture2D(src, coord);
                    gl_FragColor = vec4(vec3(dot(tex.rgb,
                                        vec3(0.344, 0.5, 0.156))),
                                             tex.a) * qt_Opacity;
                }"
        }
    }
}

Примечание: Текстуры графа сцены имеют начало в верхнем левом углу, а не в нижнем левом, как это обычно бывает в OpenGL.

Сведения о используемой версии GLSL см. в QtQuick::GraphicsInfo.

Начиная с Qt 5.8, ShaderEffect также поддерживает чтение исходного кода GLSL из файлов. В любое время, когда значение свойства fragmentShader или vertexShader является URL-адресом со схемой file или qrc, он рассматривается как ссылка на файл, и исходный код читается из указанного файла.

Direct3D и HLSL

Direct3D бэкэнды предоставляют поддержку ShaderEffect с HLSL. Direct3D 12 бэкэнд требует использования, как минимум, Shader Model 5.0 для вершинных и пиксельных шейдеров. При необходимости GraphicsInfo.shaderType можно использовать для определения в ходе выполнения того, какой тип значения назначить для fragmentShader или vertexShader.

Все концепции, описанные выше для OpenGL и GLSL, применимы и к Direct3D и HLSL. Однако есть ряд важных практических отличий:

Вместо униформ, ожидается, что HLSL шейдеры будут использовать единственный константный буфер, назначенный регистру b0. Специальные имена qt_Matrix, qt_Opacity, и qt_SubRect_<name> работают так же, как и с GLSL. Все остальные члены буфера должны сопоставляться со свойствами элемента ShaderEffect.

Примечание: Макет буфера должен быть совместим для обоих шейдеров. Это означает, что шейдеры, предоставленные приложением, должны убедиться, что qt_Matrix и qt_Opacity включены в буфер, начиная с смещения 0, когда пользовательский код предоставляется только для одного типа шейдера, что приводит к тому, что ShaderEffect предоставляет другой шейдер. Это связано с тем, что встроенный код шейдера ShaderEffect объявляет константный буфер, содержащий float4x4 qt_Matrix; float qt_Opacity;.

В отличие от атрибутов GLSL, для элементов входных данных вершин не используются имена. Поэтому qt_Vertex и qt_MultiTexCoord0 не актуальны. Вместо этого используются стандартные семантики Direct3D, POSITION и TEXCOORD (или TEXCOORD0). для определения правильного макета входных данных.

В отличие от сапплеров GLSL, объекты текстур и сапплеров разделены в HLSL. Ожидается, что шейдеры будут ожидать 2D текстуры без массивов и мультисэмплинга. Ожидается, что точки привязки текстуры и сапплера будут последовательными и начинаться с 0 (то есть, соответственно, регистры t0, t1, ..., и s0, s1, ...). В отличие от OpenGL, сапплеры не сопоставляются со свойствами элементов Qt Quick, и поэтому имя сапплера не имеет значения. Вместо этого именно текстуры сопоставляются со свойствами, ссылающимися на элементы Изображение или ShaderEffectSource.

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

Чтобы проверить поддерживаемые параметры во время выполнения, используйте свойства GraphicsInfo.shaderSourceType и GraphicsInfo.shaderCompilationType. Обратите внимание, что это битовые маски, так как некоторые бэкэнды могут поддерживать несколько подходов.

В случае Direct3D 12 все комбинации поддерживаются. Если свойства vertexShader и fragmentShader образуют допустимый URL со схемой file или qrc, байткод или исходный код HLSL читаются из указанного файла. Тип содержимого файла определяется автоматически. В противном случае строка обрабатывается как исходный код HLSL и компилируется в момент выполнения, предполагая Shader Model 5.0 и точку входа "main". Это позволяет динамически создавать строки шейдеров. Однако, когда исходный код шейдера статичен, настоятельно рекомендуется предварительно скомпилировать его в байткод с использованием инструмента fxc и ссылаться на эти файлы из QML. Это будет значительно эффективнее во время выполнения и позволит обнаруживать синтаксические ошибки в шейдерах во время компиляции.

В отличие от OpenGL, бэкэнд Direct3D может выполнять компиляцию шейдеров в режиме реального времени на выделенных потоках. Это происходит прозрачно для приложений, а это означает, что элементы ShaderEffect, содержащие строки исходного кода HLSL, не блокируют рендеринг или другие части приложения до тех пор, пока байткод не будет готов.

Использование файлов с байткодом также более гибко, когда речь идёт о имени точки входа (он может быть любым, не ограниченным main) и модели шейдера (она может быть новее 5.0, например 5.1).

import QtQuick 2.0

Rectangle {
    width: 200; height: 100
    Row {
        Image { id: img;
                sourceSize { width: 100; height: 100 } source: "qt-logo.png" }
        ShaderEffect {
            width: 100; height: 100
            property variant src: img
            fragmentShader: "qrc:/effect_ps.cso"
        }
    }
}
где effect_ps.cso — скомпилированный байткод для следующего HLSL шейдера:
cbuffer ConstantBuffer : register(b0)
{
    float4x4 qt_Matrix;
    float qt_Opacity;
};
Texture2D src : register(t0);
SamplerState srcSampler : register(s0);
float4 ExamplePixelShader(float4 position : SV_POSITION, float2 coord : TEXCOORD0) : SV_TARGET
{
    float4 tex = src.Sample(srcSampler, coord);
    float3 col = dot(tex.rgb, float3(0.344, 0.5, 0.156));
    return float4(col, tex.a) * qt_Opacity;
}

Вышеприведённый пример эквивалентен представленному ранее примеру OpenGL. Вершинный шейдер неявно предоставляется объектом ShaderEffect. Обратите внимание, что вывод пиксельного шейдера использует предварительно умноженный альфа-канал, и что qt_Matrix присутствует в буфере констант по смещению 0, хотя пиксельный шейдер не использует это значение.

При желании исходный код HLSL можно поместить непосредственно в исходный код QML, аналогично тому, как это делается с GLSL. Единственное различие в этом случае — имя точки входа, которое должно быть main при использовании встроенных исходных строк.

В качестве альтернативы, мы также могли бы сослаться на файл, содержащий исходный код эффекта, вместо скомпилированной версии байткода.

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

import QtQuick 2.0

Rectangle {
    width: 200; height: 100
    Row {
        Image { id: img;
                sourceSize { width: 100; height: 100 } source: "qt-logo.png" }
        ShaderEffect {
            width: 100; height: 100
            property variant src: img
            property variant color: Qt.vector3d(0.344, 0.5, 0.156)
            vertexShader: "qrc:/effect_vs.cso"
            fragmentShader: "qrc:/effect_ps.cso"
        }
    }
}
где effect_vs.cso и effect_ps.cso — это скомпилированный байткод для ExampleVertexShader и ExamplePixelShader. Исходный код представлен здесь одним фрагментом, но шейдеры также могут быть размещены в отдельных исходных файлах.
cbuffer ConstantBuffer : register(b0)
{
    float4x4 qt_Matrix;
    float qt_Opacity;
    float3 color;
};
Texture2D src : register(t0);
SamplerState srcSampler : register(s0);
struct PSInput
{
    float4 position : SV_POSITION;
    float2 coord : TEXCOORD0;
};
PSInput ExampleVertexShader(float4 position : POSITION, float2 coord : TEXCOORD0)
{
    PSInput result;
    result.position = mul(qt_Matrix, position);
    result.coord = coord;
    return result;
}
float4 ExamplePixelShader(PSInput input) : SV_TARGET
{
    float4 tex = src.Sample(srcSampler, coord);
    float3 col = dot(tex.rgb, color);
    return float4(col, tex.a) * qt_Opacity;
}

Примечание: В OpenGL координата y расположена снизу вверх, в то время как в Direct 3D — сверху вниз. Для исходных кодов шейдерных эффектов Qt Quick скрывает это различие, обрабатывая QtQuick::ShaderEffectSource::textureMirroring соответствующим образом, что означает, что координатам текстур в HLSL-версии шейдеров не потребуются какие-либо корректировки по сравнению с эквивалентным GLSL-кодом.

Элементы ShaderEffect кроссплатформенные и кросс-API

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

Существует два подхода для решения этой проблемы: либо записывать условные значения свойств на основе GraphicsInfo.shaderType, либо использовать селекторы файлов. На практике второй подход сильно рекомендуется, так как он приводит к более лаконичному и чистому коду приложения. Единственный случай, когда он не подходит, — это когда исходные строки строятся динамически.

import QtQuick 2.8 // for GraphicsInfo

Rectangle {
    width: 200; height: 100
    Row {
        Image { id: img;
                sourceSize { width: 100; height: 100 } source: "qt-logo.png" }
        ShaderEffect {
            width: 100; height: 100
            property variant src: img
            property variant color: Qt.vector3d(0.344, 0.5, 0.156)
            fragmentShader: GraphicsInfo.shaderType === GraphicsInfo.GLSL ?
                "varying highp vec2 coord;
                uniform sampler2D src;
                uniform lowp float qt_Opacity;
                void main() {
                    lowp vec4 tex = texture2D(src, coord);
                    gl_FragColor = vec4(vec3(dot(tex.rgb,
                                        vec3(0.344, 0.5, 0.156))),
                                             tex.a) * qt_Opacity;"
            : GraphicsInfo.shaderType === GraphicsInfo.HLSL ?
                "cbuffer ConstantBuffer : register(b0)
                {
                    float4x4 qt_Matrix;
                    float qt_Opacity;
                };
                Texture2D src : register(t0);
                SamplerState srcSampler : register(s0);
                float4 ExamplePixelShader(float4 position : SV_POSITION, float2 coord : TEXCOORD0) : SV_TARGET
                {
                    float4 tex = src.Sample(srcSampler, coord);
                    float3 col = dot(tex.rgb, float3(0.344, 0.5, 0.156));
                    return float4(col, tex.a) * qt_Opacity;
                }"
            : ""
        }
    }
}
Это первый подход, основанный на GraphicsInfo. Обратите внимание, что значение, сообщённое GraphicsInfo, не обновляется до тех пор, пока элемент ShaderEffect не будет связан с QQuickWindow. До этого сообщённое значение — GraphicsInfo.UnknownShadingLanguage. Альтернативный способ — поместить исходный код GLSL и скомпилированный D3D байткод в файлы shaders/effect.frag и shaders/+hlsl/effect.frag, включить их в систему ресурсов Qt и позволить внутреннему селектору файлов ShaderEffect, QFileSelector, выполнить свою работу. Селектор без файлов — это исходный код GLSL, а селектор hlsl используется при запуске на бэкенде D3D12. Файл по адресу +hlsl может содержать либо исходный код HLSL, либо скомпилированный байткод из инструмента fxc. Кроме того, при использовании контекста профиля ядра версии 3.2 или новее с OpenGL, исходные коды GLSL с синтаксисом, совместимым с профилем ядра, могут быть размещены в +glslcore.
import QtQuick 2.8 // for GraphicsInfo

Rectangle {
    width: 200; height: 100
    Row {
        Image { id: img;
                sourceSize { width: 100; height: 100 } source: "qt-logo.png" }
        ShaderEffect {
            width: 100; height: 100
            property variant src: img
            property variant color: Qt.vector3d(0.344, 0.5, 0.156)
            fragmentShader: "qrc:shaders/effect.frag" // selects the correct variant automatically
        }
    }
}

ShaderEffect и слои элементов

Тип ShaderEffect может быть объединён с слоистыми элементами.

Слой с отключённым эффектом Слой с включённым эффектом
Item {
    id: layerRoot
    layer.enabled: true
    layer.effect: ShaderEffect {
        fragmentShader: "
            uniform lowp sampler2D source; // this item
            uniform lowp float qt_Opacity; // inherited opacity of this item
            varying highp vec2 qt_TexCoord0;
            void main() {
                lowp vec4 p = texture2D(source, qt_TexCoord0);
                lowp float g = dot(p.xyz, vec3(0.344, 0.5, 0.156));
                gl_FragColor = vec4(g, g, g, p.a) * qt_Opacity;
            }"
    }

Также возможно объединить несколько слоистых элементов:

    Rectangle {
        id: gradientRect;
        width: 10
        height: 10
        gradient: Gradient {
            GradientStop { position: 0; color: "white" }
            GradientStop { position: 1; color: "steelblue" }
        }
        visible: false; // should not be visible on screen.
        layer.enabled: true;
        layer.smooth: true
    }

    Text {
        id: textItem
        font.pixelSize: 48
        text: "Gradient Text"
        anchors.centerIn: parent
        layer.enabled: true
        // This item should be used as the 'mask'
        layer.samplerName: "maskSource"
        layer.effect: ShaderEffect {
            property var colorSource: gradientRect;
            fragmentShader: "
                uniform lowp sampler2D colorSource;
                uniform lowp sampler2D maskSource;
                uniform lowp float qt_Opacity;
                varying highp vec2 qt_TexCoord0;
                void main() {
                    gl_FragColor =
                        texture2D(colorSource, qt_TexCoord0)
                        * texture2D(maskSource, qt_TexCoord0).a
                        * qt_Opacity;
                }
            "
        }
    }

Дополнительные заметки

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

Модуль Qt Графические эффекты содержит несколько готовых эффектов для использования с приложениями Qt Quick.

См. также Слои элементов.

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

blending : bool

Если это свойство истинно, вывод из fragmentShader смешивается с фоном с помощью режима смешивания source-over. Если ложно, фон игнорируется. Смешивание снижает производительность, поэтому вы должны установить это свойство в ложь, когда смешивание не требуется. Значение по умолчанию — истина.

cullMode : перечисление

Это свойство определяет, какие стороны элемента должны быть видны.

  • ShaderEffect.NoCulling — обе стороны видны
  • ShaderEffect.BackFaceCulling — видна только передняя сторона
  • ShaderEffect.FrontFaceCulling — видна только задняя сторона

Значение по умолчанию — NoCulling.

fragmentShader : строка

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

В GLSL шейдер по умолчанию ожидает, что координата текстуры будет передана вершинным шейдером как varying highp vec2 qt_TexCoord0, и он сэмплирует из сапплера2D под названием source. В HLSL текстура называется source, а вершинный шейдер ожидается, что предоставит float2 coord : TEXCOORD0 в своём выводе, помимо float4 position : SV_POSITION (имена могут отличаться, так как линковка выполняется на основе семантики).

См. также vertexShader и GraphicsInfo.

log : строка

Это свойство содержит журнал предупреждений и ошибок, полученных при последней попытке компиляции и линковки программы шейдеров OpenGL. Оно обновляется одновременно с status, установленным в Compiled или Error.

См. также status.

mesh : вариант

Это свойство определяет сетку, используемую для отрисовки ShaderEffect. Оно может содержать любой объект GridMesh. Если свойству присвоено значение размера, ShaderEffect неявно использует GridMesh с этим значением в качестве разрешения сетки. По умолчанию это свойство имеет размер 1x1.

См. также GridMesh.

status : перечисление

Это свойство показывает текущий статус программы шейдеров OpenGL.

  • ShaderEffect.Compiled — программа шейдеров была успешно скомпилирована и пролинкована.
  • ShaderEffect.Uncompiled — программа шейдеров ещё не была скомпилирована.
  • ShaderEffect.Error — программа шейдеров не удалось скомпилировать или пролинковать.

При установке исходного кода фрагментного или вершинного шейдера статус станет Uncompiled. При первом рендеринге ShaderEffect с новым исходным кодом шейдеров, шейдеры компилируются и линкованы, и статус обновляется до Compiled или Error.

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

См. также log.

supportsAtlasTextures : bool

Установите это свойство в true, чтобы подтвердить, что ваш код шейдера не зависит от qt_MultiTexCoord0, варьирующегося от (0,0) до (1,1) относительно сетки. В этом случае диапазон qt_MultiTexCoord0 будет скорее основан на позиции текстуры в атласе. Это свойство в настоящее время не оказывает влияния, если используется меньше или больше одного униформ-сапплера в качестве входных данных для вашего шейдера.

Это отличается от предоставления униформ qt_SubRect_<имя>, так как последнее позволяет отрисовать одну или несколько текстур из атласа в одном элементе ShaderEffect, а supportsAtlasTextures позволяет многократно использовать компонент ShaderEffect с использованием различных исходных изображений из атласа в одной отрисовке. Оба предотвращают копирование текстуры из атласа при ссылке на неё элементом ShaderEffect.

Значение по умолчанию — ложь.

Это свойство было введено в QtQuick 2.4.

vertexShader : строка

Это свойство содержит исходный код вершинного шейдера или ссылку на предварительно скомпилированный байткод. Некоторые API, такие как OpenGL, всегда поддерживают компиляцию во время выполнения, и поэтому традиционный способ Qt Quick встраивания строк исходного кода шейдера функционален. Однако бэкэнды Qt Quick для других API могут ограничивать поддержку предварительно скомпилированным байткодом, таким как SPIR-V или D3D-байткод шейдера. В этом случае строка просто является именем файла, который может быть файлом в файловой системе или скомпилирован в исполняемый файл через систему ресурсов Qt.

С GLSL по умолчанию шейдер передает текстурные координаты фрагмент-шейдеру как varying highp vec2 qt_TexCoord0. В HLSL достаточно использовать стандартную семантику TEXCOORD0, например float2 coord : TEXCOORD0.

См. также fragmentShader и GraphicsInfo.

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

Spec-Zone.ru

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