Тип QML ShaderEffect
Применяет пользовательские шейдеры к прямоугольнику. Подробнее...
| Заявление об импорте: | import QtQuick |
| Наследует: |
Свойства
- смешивание : bool
- режим обрезки : перечисление
- фрагментный шейдер : url
- журнал : строка
- сетка : вариант
- состояние : перечисление
- поддерживает текстуры атласа : bool
- вершинный шейдер : url
Подробное описание
Тип ShaderEffect применяет пользовательский шейдер вершины и шейдер фрагмента (пикселя) к прямоугольнику. Это позволяет добавлять эффекты, такие как тень, размытие, изменение цвета и перелистывание страницы, в сцену QML.
Примечание: В зависимости от используемого бэкенда Qt Quick, тип ShaderEffect может не поддерживаться. Например, с бэкендом software эффекты вообще не будут отображаться.
Шейдеры
В Qt 5 эффекты предоставлялись в виде исходного кода GLSL (OpenGL Shading Language), часто встроенного в виде строк в QML. Начиная с Qt 5.8, стало возможным обращение к файлам, как локальным, так и из системы ресурсов Qt.
В Qt 6 Qt Quick поддерживает графические API, такие как Vulkan, Metal и Direct3D 11. Поэтому работа с исходными строками GLSL больше невозможна. Вместо этого новый конвейер шейдеров основан на компиляции совместимого с Vulkan кода GLSL в SPIR-V, за которым следует сбор информации о рефлексии и перевод на другие языки шейдеров, такие как HLSL, Metal Shading Language и различные версии GLSL. Результирующие ресурсы упаковываются в единый пакет, обычно хранящийся в файлах с расширением .qsb. Этот процесс выполняется автономно или во время сборки приложения. В момент выполнения, графический абстрактный уровень и сцена используются этими файлами .qsb. Поэтому ShaderEffect ожидает ссылки на файлы (локальные или qrc) в Qt 6 вместо встроенного кода шейдеров.
Свойства vertexShader и fragmentShader являются URL-адресами в Qt 6 и работают очень похоже на Image.source, например. Однако поддерживаются только схемы file и qrc с ShaderEffect. Также можно опустить схему file, что позволяет удобно указывать относительный путь. Такой путь разрешается относительно расположения компонента (файла .qml).
Входные данные и ресурсы шейдеров
Существует два типа входных данных для vertexShader: переменные и входные данные вершин.
Предопределены следующие входные данные:
- vec4 qt_Vertex с местоположением 0 - позиция вершины, верхняя левая вершина имеет координаты (0, 0), нижняя правая (ширина, высота).
- vec2 qt_MultiTexCoord0 с местоположением 1 - координаты текстуры, верхняя левая координата — (0, 0), нижняя правая (1, 1). Если supportsAtlasTextures истинно, координаты будут основаны на позиции в атласе.
Примечание: На практике имеет значение только местоположение входных данных вершины. Имена можно изменять свободно, а местоположение должно всегда быть 0 для позиции вершины, 1 для координат текстуры. Однако имейте в виду, что это относится только к входным данным вершины, и это необязательно верно для выходных переменных из вершинного шейдера, которые затем используются в качестве входных данных в фрагментном шейдере (обычно интерполированные координаты текстуры).
Предопределены следующие униформы:
- mat4 qt_Matrix - комбинированная матрица преобразования, произведение матриц от корневого элемента до этого ShaderEffect и ортогональной проекции.
- float qt_Opacity - комбинированная непрозрачность, произведение непрозрачностей от корневого элемента до этого ShaderEffect.
Примечание: Стиль GLSL в стиле Vulkan не имеет отдельных переменных униформ. Вместо этого шейдеры должны всегда использовать блок униформ с точкой привязки 0.
Примечание: Квалификатор макета блока униформ должен всегда быть std140.
Примечание: В отличие от входных данных вершины, предопределенные имена (qt_Matrix, qt_Opacity) не должны изменяться.
Кроме того, любые свойства, которые можно отобразить в типе 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 - Начало в верхнем левом углу, и значения цвета предварительно умножены. Текстура предоставляется как есть, за исключением fillMode элемента Image. Для включения fillMode используйте ShaderEffectSource или Image::layer::enabled.
- ShaderEffectSource -> sampler2D - Начало в верхнем левом углу, и значения цвета предварительно умножены.
Сэмплеры по-прежнему объявляются как отдельные переменные униформ в коде шейдера. Шейдеры могут свободно выбирать любую точку привязки для них, за исключением 0, поскольку она зарезервирована для блока униформ.
Некоторые языки и API шейдеров имеют понятие отдельных объектов изображения и сэмплера. Qt Quick всегда работает с объединенными объектами сэмплера изображения в шейдерах, как поддерживается SPIR-V. Поэтому шейдеры, предоставленные для ShaderEffect, должны всегда использовать стиль layout(binding = 1) uniform sampler2D tex; объявления сэмплеров. Базовая абстракция и конвейер шейдеров позаботятся об этом, работая прозрачно для приложений.
Бэкенд 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 должны быть предварительно умножены. Если смешивание включено, используется смешивание 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: "myeffect.vert.qsb"
fragmentShader: "myeffect.frag.qsb"
}
}
} |
Пример предполагает, что myeffect.vert и myeffect.frag содержат код GLSL в стиле Vulkan, обработанный инструментом qsb для генерации файлов .qsb.
#version 440
layout(location = 0) in vec4 qt_Vertex;
layout(location = 1) in vec2 qt_MultiTexCoord0;
layout(location = 0) out vec2 coord;
layout(std140, binding = 0) uniform buf {
mat4 qt_Matrix;
float qt_Opacity;
};
void main() {
coord = qt_MultiTexCoord0;
gl_Position = qt_Matrix * qt_Vertex;
} #version 440
layout(location = 0) in vec2 coord;
layout(location = 0) out vec4 fragColor;
layout(std140, binding = 0) uniform buf {
mat4 qt_Matrix;
float qt_Opacity;
};
layout(binding = 1) uniform sampler2D src;
void main() {
vec4 tex = texture(src, coord);
fragColor = vec4(vec3(dot(tex.rgb, vec3(0.344, 0.5, 0.156))), tex.a) * qt_Opacity;
} Примечание: Текстуры графической сцены имеют начало в верхнем левом углу, а не в нижнем левом, как это обычно используется в OpenGL.
Использование только одного шейдера
Указание как vertexShader, так и fragmentShader не обязательно. Многие реализации ShaderEffect на практике захотят предоставить только фрагментный шейдер, полагаясь на стандартный встроенный вершинный шейдер.
Стандартный вершинный шейдер передает координату текстуры фрагментному шейдеру как vec2 qt_TexCoord0 в местоположении 0.
Стандартный фрагментный шейдер ожидает, что координата текстуры будет передана вершинным шейдером как vec2 qt_TexCoord0 в местоположении 0, и он будет брать образец из sampler2D под названием source в точке привязки 1.
Предупреждение: При указании только одного из шейдеров автор шейдера должен учитывать ожидаемый макет блока униформ стандартных шейдеров: qt_Matrix должен всегда находиться в смещении 0, а за ним — qt_Opacity в смещении 64. Любые пользовательские униформы должны быть размещены после этих двух. Это обязательно даже тогда, когда шейдер, предоставленный приложением, не использует матрицу или непрозрачность, потому что в момент выполнения существует один единственный буфер униформ, который доступен как вершинному, так и фрагменному шейдеру.
Предупреждение: В отличие от вершинных входов, передача данных между вершинным и фрагментным шейдерами, в зависимости от используемого графического API, может потребовать одинаковых имён. Соответствие местоположения не всегда достаточно. Особенно, когда используется фрагментный шейдер с использованием по умолчанию встроенного вершинного шейдера, координаты текстуры передаются как qt_TexCoord0 в местоположении 0, поэтому настоятельно рекомендуется, чтобы фрагментный шейдер объявлял вход с тем же именем (qt_TexCoord0). Отсутствие этого может привести к проблемам на некоторых платформах, например, при работе с контекстом OpenGL без использования основного профиля, где исходный код GLSL-шейдера не имеет квалификаторов местоположения, а соответствие основано на именах переменных во время процесса связывания шейдеров.
Эффект шейдера и слои элементов
Тип ShaderEffect можно комбинировать с слоистыми элементами.
|
Слой с отключенным эффектом |
Слой с включенным эффектом |
Item {
id: layerRoot
layer.enabled: true
layer.effect: ShaderEffect {
fragmentShader: "effect.frag.qsb"
}
} #version 440
layout(location = 0) in vec2 qt_TexCoord0;
layout(location = 0) out vec4 fragColor;
layout(std140, binding = 0) uniform buf {
mat4 qt_Matrix;
float qt_Opacity;
};
layout(binding = 1) uniform sampler2D source;
void main() {
vec4 p = texture(source, qt_TexCoord0);
float g = dot(p.xyz, vec3(0.344, 0.5, 0.156));
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: "mask.frag.qsb"
}
} #version 440
layout(location = 0) in vec2 qt_TexCoord0;
layout(location = 0) out vec4 fragColor;
layout(std140, binding = 0) uniform buf {
mat4 qt_Matrix;
float qt_Opacity;
};
layout(binding = 1) uniform sampler2D colorSource;
layout(binding = 2) uniform sampler2D maskSource;
void main() {
fragColor = texture(colorSource, qt_TexCoord0)
* texture(maskSource, qt_TexCoord0).a
* qt_Opacity;
} |
Другие заметки
По умолчанию ShaderEffect состоит из четырёх вершин, по одной на каждый угол. Для нелинейных преобразований вершин, таких как изгиб страницы, можно указать тонкую сетку вершин, задав разрешение сетки через свойство mesh.
Миграция с Qt 5
Для приложений Qt 5 с элементами ShaderEffect миграция в Qt 6 включает:
- Перемещение кода шейдера в отдельные
.vertи.fragфайлы, - обновление шейдеров до совместимого с Vulkan GLSL,
- запуск инструмента
qsbна них, - включение полученных
.qsbфайлов в исполняемый файл с помощью системы ресурсов Qt, - и ссылку на файл в свойствах vertexShader и fragmentShader.
Как описано в модуле Qt Shader Tools, некоторые из этих шагов можно автоматизировать, позволив CMake вызвать инструмент qsb во время сборки. Подробнее см. Интеграция системы сборки Qt Shader Tools.
При обновлении кода шейдеров ниже приведён обзор обычно необходимых изменений.
| Вершинный шейдер в Qt 5 | Вершинный шейдер в Qt 6 |
|---|---|
attribute highp vec4 qt_Vertex;
attribute highp vec2 qt_MultiTexCoord0;
varying highp vec2 coord;
uniform highp mat4 qt_Matrix;
void main() {
coord = qt_MultiTexCoord0;
gl_Position = qt_Matrix * qt_Vertex;
} |
#version 440
layout(location = 0) in vec4 qt_Vertex;
layout(location = 1) in vec2 qt_MultiTexCoord0;
layout(location = 0) out vec2 coord;
layout(std140, binding = 0) uniform buf {
mat4 qt_Matrix;
float qt_Opacity;
};
void main() {
coord = qt_MultiTexCoord0;
gl_Position = qt_Matrix * qt_Vertex;
} |
Процесс преобразования в основном заключается в обновлении кода для совместимости с GL_KHR_vulkan_glsl. Стоит отметить, что Qt Quick использует подмножество функций, предоставляемых GLSL и Vulkan, и поэтому процесс преобразования для типичных шейдеров ShaderEffect обычно является простым.
- Директива
versionдолжна указывать440или450, хотя и другие версии GLSL могут работать, поскольку расширение GL_KHR_vulkan_glsl написано для GLSL 140 и выше. - Входы и выходы должны использовать современные ключевые слова GLSL
inиout. Кроме того, требуется указание местоположения. Пространства имён для местоположений ввода и вывода разделены, поэтому присваивание местоположений, начиная с 0, для обоих является безопасным. - Что касается входов вершинного шейдера, единственными возможностями с ShaderEffect являются местоположение
0для координат вершины (традиционно называемогоqt_Vertex) и местоположение1для координат текстуры (традиционно называемогоqt_MultiTexCoord0). - Выходы вершинного шейдера и входы фрагментного шейдера определяются кодом шейдера. Фрагментный шейдер должен иметь выход
vec4в местоположении 0 (обычно называетсяfragColor). Для максимальной переносимости выходы вершин и входы фрагментов должны использовать и то же число местоположения, и то же имя. При указании только фрагментного шейдера координаты текстуры передаются встроенным вершинным шейдером какvec2 qt_TexCoord0в местоположении0, как показано в примерах фрагментов кода выше. - Переменные униформы вне блока униформ не являются допустимыми. Вместо этого данные униформ должны быть объявлены в блоке униформ с точкой привязки
0. - Ожидается, что блок униформ будет использовать квалификатор std140.
- Во время выполнения вершинный и фрагментный шейдеры получат один и тот же буфер униформ, привязанный к точке привязки 0. Поэтому, как общее правило, объявления блока униформ должны быть идентичными между шейдерами. Это также включает члены, которые не используются в одном из шейдеров. Имена членов должны совпадать, поскольку с некоторыми графическими API блок униформ преобразуется в традиционную структуру униформы, прозрачно для приложения.
- При предоставлении одного из шейдеров будьте внимательны к тому факту, что встроенные шейдеры ожидают
qt_Matrixиqt_Opacityв верхней части блока униформ. (точнее, со смещением 0 и 64 соответственно) Как общее правило, всегда включайте их в качестве первого и второго членов блока. - В примере блок униформ указывает имя блока
buf. Это имя можно изменять свободно, но оно должно совпадать между шейдерами. Использование имени экземпляра, например,layout(...) uniform buf { ... } instance_name;, является необязательным. При указании все обращения к членам должны быть квалифицированы именем экземпляра.
| Фрагментный шейдер в Qt 5 | Фрагментный шейдер в Qt 6 |
|---|---|
varying highp vec2 coord;
uniform lowp float qt_Opacity;
uniform sampler2D src;
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;
} |
#version 440
layout(location = 0) in vec2 coord;
layout(location = 0) out vec4 fragColor;
layout(std140, binding = 0) uniform buf {
mat4 qt_Matrix;
float qt_Opacity;
};
layout(binding = 1) uniform sampler2D src;
void main() {
vec4 tex = texture(src, coord);
fragColor = vec4(vec3(dot(tex.rgb,
vec3(0.344, 0.5, 0.156))),
tex.a) * qt_Opacity;
} |
- Квалификаторы точности (
lowp,mediump,highp) в настоящее время не используются. - Вызов встроенных функций GLSL должен следовать современным именам GLSL, в частности,
texture()вместоtexture2D(). - Самплер должны использовать точки привязки, начиная с 1.
См. также Слои элементов, Справочник QSB и Интеграция системы сборки Qt Shader Tools.
Документация свойств
blending : bool
Если это свойство имеет значение true, вывод из fragmentShader смешивается с фоном с использованием режима смешивания source-over. Если false, фон игнорируется. Смешивание снижает производительность, поэтому следует устанавливать это свойство в false, когда смешивание не требуется. Значение по умолчанию — true.
cullMode : перечисление
Это свойство определяет, какие стороны элемента должны быть видимыми.
- ShaderEffect.NoCulling - Обе стороны видны
- ShaderEffect.BackFaceCulling - Видна только передняя сторона
- ShaderEffect.FrontFaceCulling - Видна только задняя сторона
По умолчанию используется NoCulling.
fragmentShader : url
Это свойство содержит ссылку на файл с предварительно обработанным фрагментным шейдерным пакетом, обычно с расширением .qsb. Значение обрабатывается как URL, аналогично другим типам QML, таким как Image. Он должен либо быть локальным файлом, либо использовать схему qrc для доступа к файлам, встроенным с помощью системы ресурсов Qt. URL может быть абсолютным или относительным к URL компонента.
См. также vertexShader.
log : строка
Это свойство содержит журнал предупреждений и ошибок последней попытки компиляции шейдеров. Оно обновляется в то же время, когда status устанавливается в Compiled или Error.
Примечание: В Qt 6 процесс обработки шейдеров продвинут, поддерживая компиляцию и преобразование шейдеров GLSL-стиля Vulkan вне линии или во время сборки. Это не обязательно означает, что компиляции шейдеров нет во время выполнения, но даже если она есть, ShaderEffect в этом не участвует, и синтаксические и подобные ошибки больше не должны возникать на этом этапе. Поэтому значение этого свойства обычно пустое.
См. также status.
mesh : значения
Это свойство определяет сетку, используемую для отрисовки ShaderEffect. Оно может содержать любой объект GridMesh. Если свойству присваивается значение размера, ShaderEffect неявно использует GridMesh с этим значением в качестве разрешения сетки. По умолчанию это свойство имеет размер 1x1.
См. также GridMesh.
status : перечисление
Это свойство указывает текущий статус шейдеров.
- ShaderEffect.Compiled - программа шейдера была успешно скомпилирована и связана.
- ShaderEffect.Uncompiled - программа шейдера ещё не была скомпилирована.
- ShaderEffect.Error - программа шейдера не смогла быть скомпилирована или связана.
При установке исходного кода фрагментного или вершинного шейдера статус становится Uncompiled. При первом отрисовке ShaderEffect с новым исходным кодом шейдера шейдеры компилируются и связываются, а статус обновляется до Compiled или Error.
Когда компиляция во время выполнения не используется, и свойства шейдера ссылаются на файлы с байткодом, статус всегда Compiled. Содержимое шейдера не проверяется (кроме базового отражения для обнаружения элементов вершинного входа и данных буфера констант) до более поздних этапов конвейера отрисовки, поэтому потенциальные ошибки (например, несовпадения макета или подписи корня) будут обнаружены только на более позднем этапе.
См. также log.
[с QtQuick 2.4] supportsAtlasTextures : bool
Установите значение этого свойства в true, чтобы подтвердить, что ваш шейдерный код не полагается на qt_MultiTexCoord0, изменяющийся в пределах от (0,0) до (1,1) относительно сетки. В этом случае диапазон qt_MultiTexCoord0 будет скорее основан на расположении текстуры внутри атласа. В настоящее время это свойство не оказывает влияния, если в качестве входных данных в ваш шейдер используется менее или более одного униформа-самплера.
Это отличается от предоставления униформ qt_SubRect_<имя>, так как последнее позволяет рисовать одну или несколько текстур из атласа в одном элементе ShaderEffect, в то время как supportsAtlasTextures позволяет многократно использовать компонент ShaderEffect с использованием различного изображения из атласа для объединения в одном рисунке. Оба варианта предотвращают копирование текстуры из атласа, когда она ссылается на элемент ShaderEffect.
Значение по умолчанию — false.
Это свойство было добавлено в QtQuick 2.4.
vertexShader : url
Это свойство содержит ссылку на файл с предварительно обработанным пакетом вершинного шейдера, обычно с расширением .qsb. Значение обрабатывается как URL, аналогично другим типам QML, таким как Image. Оно должно быть либо локальным файлом, либо использовать схему qrc для доступа к файлам, встроенным через систему ресурсов Qt. URL может быть абсолютным или относительным по отношению к URL компонента.
См. также fragmentShader.
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-6.2/qml-qtquick-shadereffect.html