Spec-Zone.ru › Qt 5.9

Тип QML ShaderEffect

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

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

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), доступна в качестве переменной униформы. Следующий список показывает, как свойства отображаются в переменных униформ 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 обычно предпочитают внештальную компиляцию и поставляют предварительно скомпилированный байткод с приложениями, вместо встраиваемых строк исходного кода шейдеров. В этом случае строковые свойства для вершинных и фрагментных шейдеров рассматриваются как URL-адреса, ссылающиеся на локальные файлы или файлы, отправленные через систему ресурсов 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 выполнить свою работу. Бесселекторная версия — это исходный код 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 Graphical Effects содержит несколько готовых эффектов для использования в приложениях Qt Quick.

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

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

blending : bool

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

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, и он обращается к текстуре из объекта sampler2D с именем source. В HLSL имя текстуры — source, в то время как вершинный шейдер должен предоставить float2 coord : TEXCOORD0 в своём выходе помимо float4 position : SV_POSITION (имена могут отличаться, так как связывание выполняется на основе семантики).

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

log : строка

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

См. также status.

mesh : variant

Это свойство определяет сетку, используемую для отрисовки 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_<name>, так как последнее позволяет рисовать одну или несколько текстур из атласа в одном элементе ShaderEffect, в то время как supportsAtlasTextures позволяет нескольким экземплярам компонента ShaderEffect, использующим различные исходные изображения из атласа, быть объединены в одном рисунке. Оба способа предотвращают копирование текстуры из атласа при ссылке на неё элементом ShaderEffect.

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

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

vertexShader : string

Это свойство содержит исходный код шейдера вершин или ссылку на предварительно скомпилированный байткод. Некоторые 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.9/qml-qtquick-shadereffect.html

Spec-Zone.ru

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