Spec-Zone.ru › Qt 5.15

Тип QML ShaderEffect

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

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

Item

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

Свойства

  • 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), нижняя правая (width, height).
  • attribute vec2 qt_MultiTexCoord0 — координаты текстуры, верхняя левая координата (0, 0), нижняя правая (1, 1). Если supportsAtlasTextures имеет значение true, координаты будут основаны на положении в атласе вместо этого.

Кроме того, все свойства, которые можно отобразить в типе OpenGL Shading Language (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.
  • Image -> sampler2D — Начало в верхнем левом углу, а значения цвета предварительно умножены. Текстура предоставляется как есть, за исключением режима заполнения элемента Image. Для включения режима заполнения используйте ShaderEffectSource или Image::layer::enabled.
  • ShaderEffectSource -> sampler2D — Начало в верхнем левом углу, а значения цвета предварительно умножены.

Бэкэнд QML графической сцены может выбрать выделение текстур в атласах текстур. Если текстура, выделенная в атласе, передается в ShaderEffect, она по умолчанию копируется из атласа текстур в отдельную текстуру, чтобы координаты текстуры были в диапазоне от 0 до 1, и вы получите ожидаемые режимы обрезки. Однако это увеличит использование памяти. Чтобы избежать копирования текстуры, установите supportsAtlasTextures для простых шейдеров, использующих qt_MultiTexCoord0, или для каждого "uniform sampler2D <name>" объявляйте "uniform vec4 qt_SubRect_<name>", которые будут назначены нормализованному прямоугольнику источника текстуры. Для самостоятельных текстур прямоугольник источника составляет [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, поэтому имя сапплера не имеет значения. Вместо этого текстуры отображаются на свойства, ссылающиеся на элементы Image или ShaderEffectSource.

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

Для проверки поддержки в режиме выполнения используйте свойства 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.15/qml-qtquick-shadereffect.html

Spec-Zone.ru

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