ShaderEffect QML 类型
将自定义着色器应用于矩形。 更多...
导入语句 | import QtQuick |
继承 |
属性
- blending : bool
- cullMode : 枚举
- fragmentShader : url
- log : 字符串
- mesh : 变体
- status : 枚举
- supportsAtlasTextures : bool
(自 QtQuick 2.4)
- vertexShader : url
详细描述
ShaderEffect 类型将自定义的 顶点 和 片段(像素) 着色器应用于矩形。它允许将像阴影、模糊、着色和翻页等效果添加到 QML 场景中。
注意: 根据使用的 Qt Quick 场景图后端,可能不支持 ShaderEffect 类型。例如,使用 software
后端时,效果将完全不会渲染。
着色器
在 Qt 5 中,效果以 GLSL(OpenGL 着色语言)源代码的形式提供,通常作为字符串嵌入到 QML 中。从 Qt 5.8 开始,也可以引用文件,无论是本地文件还是 Qt 资源系统中的文件。
在 Qt 6 中,Qt Quick 也支持图形 API,例如 Vulkan、Metal 和 Direct3D 11。因此,使用 GLSL 源字符串已不再可行。相反,新的着色器管道是基于将与 Vulkan 兼容的 GLSL 代码编译成 SPIR-V,然后收集反射信息并将其转换为其他着色语言,例如 HLSL、Metal 着色语言和各种 GLSL 版本。生成的资产被打包成一个单一的包,通常以 .qsb
扩展名保存的文件中。此过程在离线或在应用程序构建时最新完成。在运行时,场景图和底层图形抽象消耗这些 .qsb
文件。因此,ShaderEffect 在 Qt 6 中期望文件(本地或 qrc)引用,而不是内联着色器代码。
在 Qt 6 中,vertexShader 和 fragmentShader 属性是 URL,它们工作方式与 Image.source 非常相似。但是,ShaderEffect 只支持 file
和 qrc
两种方案。还可以省略 file
方案,以方便的方式指定相对路径。这样的路径是在组件的位置(即 .qml
文件的位置)解析的。
着色器输入和资源
vertexShader 有两种类型的输入:uniform 和 vertex inputs。
以下输入是预定义的
- vec4 qt_Vertex 位置 0 - 顶点位置,左上角的顶点位置为 (0, 0),右下角位置为 (width, height)。
- vec2 qt_MultiTexCoord0 位置 1 - 纹理坐标,左上角坐标为 (0, 0),右下角为 (1, 1)。如果 supportsAtlasTextures 为 true,则坐标将基于图集中的位置。
注意:实际上只有顶点输入的位置很重要。名称可以自由更改,而位置必须是 0
以表示顶点位置,1
以表示纹理坐标。然而,请注意,这仅适用于顶点输入,对于顶点着色器作为片段着色器输入使用的输出变量(通常是插值纹理坐标)则不必如此。
以下 uniform 预定义为
- mat4 qt_Matrix - 组合变换矩阵,从根项到此 ShaderEffect 矩阵的乘积和一个正交投影。
- float qt_Opacity - 组合不透明度,从根项到此 ShaderEffect 不透明度的乘积。
注意:与 Vulkan 风格的 GLSL 不同,没有单独的 uniform 变量。取而代之的是,着色器必须始终使用具有绑定点 0
的 uniform 块。
注意:uniform 块布局限定符必须始终为 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 - 原点位于左上角,颜色值是预先乘以的。纹理按原样提供,不包括 Image 项的填充模式。要包括填充模式,请使用 ShaderEffectSource 或 Image::layer::enabled。
- ShaderEffectSource -> sampler2D - 原点位于左上角,颜色值是预乘的。
在着色器代码中,采样器仍然声明为独立的统一变量。着色器可以自由选择这些变量的任何绑定点,除了 0
,因为这被保留用于统一块。
一些着色语言和API有一个概念,即分离的图像和采样器对象。Qt Quick始终与着色器中的复合图像采样器对象一起工作,这是SPIR-V支持的。因此,为ShaderEffect提供的着色器应该始终使用layout(binding = 1) uniform sampler2D tex;
样式的采样器声明。底层的抽象层和着色器管道负责在所有支持的API和着色语言中透明地使这一切工作。
场景图的底层可能选择在纹理图集中分配纹理。如果在图集中分配的纹理传递给ShaderEffect,它默认会从纹理图集复制到独立纹理中,以便纹理坐标从0到1,并得到期望的包装模式。然而,这将增加内存使用量。为了避免复制纹理,为使用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"。
片段着色器的输出应该是预乘的。如果启用了blending,使用源覆盖融合。然而,可以通过在alpha通道输出零来实现添加融合。
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
包含Vulkan风格的GLSL代码,由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
传递纹理坐标,并从绑定点1
的名为source
的sampler2D中采样。
警告:当只指定其中一个着色器时,着色器的编写者必须知道默认着色器预期的统一块布局:qt_Matrix必须始终位于偏移量0,后面是qt_Opacity位于偏移量64。任何自定义统一变量必须放在这两个之后。即使在应用程序提供的着色器不使用矩阵或不透明度的情况下,这也是强制性的,因为运行时有一个统一的缓冲区被暴露给顶点着色器和片段着色器。
警告:与顶点输入不同,在顶点着色器和片段着色器之间传递数据可能,根据底层图形API,需要使用相同名称,匹配位置并不总是足够。最明显的是,在指定片段着色器并依赖默认的内置顶点着色器时,纹理坐标作为 qt_TexCoord0
在位置 0
上传递,因此强烈建议片段着色器使用相同的名称(qt_TexCoord0)声明输入。未能这样做可能会导致某些平台上的问题,例如,在非核心配置的OpenGL上下文中运行时,底层GLSL着色器源代码没有位置限定符,相关匹配基于着色器链接过程中的变量名称。
ShaderEffect和项目图层
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由四个顶点组成,每个角一个。对于非线性顶点变换,如翻页,您可以通过指定一个网格分辨率来指定一个精细的顶点网格。
从Qt 5迁移
对于具有ShaderEffect项的Qt 5应用程序,迁移到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
)对应的纹理坐标。 - 顶点着色器输出和片段着色器输入由着色器代码定义。片段着色器必须有一个在位置0(通常称为
fragColor
)的vec4
输出。为了最大程度的可移植性,顶点输出和片段输入应使用相同的定位号和相同的名称。当仅指定片段着色器时,纹理坐标作为vec2 qt_TexCoord0
在位置0
由内置顶点着色器传入,如上面示例片段所示。 - 不在uniform块之外的uniform变量是非法的。相反,uniform数据必须声明在绑定点
0
的uniform块中。 - 预期uniform块将使用std140限定符。
- 在运行时,顶点着色器和片段着色器将获取绑定到绑定点0的相同uniform缓冲区。因此,作为一般规则,着色器之间的uniform块声明必须相同。这也包括在某个着色器中未使用的成员。成员名称必须匹配,因为在某些图形API中,uniform块被透明地转换为传统的struct uniform。
- 当只提供一个着色器时,请注意内置着色器期望uniform块顶部有
qt_Matrix
和qt_Opacity
。(更精确地,分别位于偏移量0和64处)作为一般规则,始终将这些作为块的第一和第二成员。 - 在示例中,uniform块指定了块名称
buf
。这个名称可以随意更改,但必须在着色器之间匹配。使用实例名称,例如layout(...) uniform buf { ... } instance_name;
是可选的。当指定时,所有对成员的访问都必须带有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着色器工具构建系统集成。
属性文档
blending : bool |
如果此属性为true,则使用source-over混合模式将来自 fragmentShader 的输出与背景混合。如果为false,则忽略背景。混合会降低性能,因此当不需要混合时,应将此属性设置为false。默认值为true。
cullMode : enumeration |
此属性定义了项目的哪些面应可见。
常数 | 描述 |
---|---|
ShaderEffect.NoCulling | 两侧都可见 |
ShaderEffect.BackFaceCulling | 仅前侧面可见 |
ShaderEffect.FrontFaceCulling | 仅后侧面可见 |
默认为NoCulling。
fragmentShader : url |
此属性包含对预处理的片段着色器包文件的引用,通常具有 .qsb
扩展名。值被处理为一个 URL,类似于其他QML类型,如Image。它必须是本地文件或使用qrc方案通过Qt资源系统访问嵌入的文件。URL可以是绝对的,也可以是相对于组件URL的相对路径。
另请参阅vertexShader。
log : string |
此属性包含最新尝试编译着色器时发生的警告和错误日志。它在将状态设置为已编译或错误时更新。
注意:在 Qt 6 中,着色器管道促进在离线或在构建时(最迟)编译和转换 Vulkan 风格的 GLSL 着色器。这并不一定意味着运行时没有进行着色器编译,但如果确实发生了,则 ShaderEffect 不参与其中,且在该阶段不应再出现语法和类似错误。因此,此属性的值通常是空的。
另请参阅:状态。
mesh : variant |
此属性定义用于绘制 ShaderEffect 的网格。它可以持有任何 GridMesh 对象。如果为此属性分配了大小值,则 ShaderEffect 隐式使用 GridMesh,其值为 网格分辨率。默认情况下,此属性的大小为 1x1。
另请参阅:GridMesh。
status : 枚举 |
此属性通知着色器的当前状态。
常数 | 描述 |
---|---|
ShaderEffect.Compiled | 着色器程序成功编译和链接。 |
ShaderEffect.Uncompiled | 着色器程序尚未编译。 |
ShaderEffect.Error | 着色器程序编译或链接失败。 |
在设置片元着色器或顶点着色器源代码时,状态将变为未编译。第一次以新的着色器源代码绘制 ShaderEffect 时,将编译和链接着色器,并更新状态为已编译或错误。
当未使用运行时编译,且着色器属性引用包含的字节码文件时,状态始终是已编译。着色器的内窖不会检查(除了基本的反射来发现顶点输入元素和常数缓冲区数据)直到渲染管道的更晚阶段,因此潜在的错误(如布局或根签名不匹配)将只在稍后检测到。
另请参阅:日志。
supportsAtlasTextures : bool |
将此属性设置为 true 以确认您的着色器代码不依赖于以 (0,0) 到 (1,1) 的范围相对于网格的 qt_MultiTexCoord0。在这种情况下,qt_MultiTexCoord0 的范围将基于纹理在纹理图集中的位置。如果使用超多采样器统一变量作为着色器输入,则此属性目前没有任何效果。
这与提供 qt_SubRect_<name> 合成无关,后一种方法允许在单个 ShaderEffect 项中绘制一个或多个来自纹理图集的纹理,而 supportsAtlasTextures 允许使用来自纹理图集的不同源图像的多个 ShaderEffect 组件实例在一个绘制中进行批量处理。两者都防止由 ShaderEffect 引用的纹理从纹理图中复制出来。
默认值为 false。
此属性是在 QtQuick 2.4 中引入的。
vertexShader : url |
此属性包含对预处理的顶点着色器包的文件的引用,通常文件扩展名为 .qsb
。该值被视为一个 URL,类似于其他 QML 类型,例如 Image。它必须是一个本地文件或使用 qrc 议程来访问通过 Qt 资源系统嵌入的文件。URL 可以是绝对的,也可以相对于组件的 URL。
另请参阅 fragmentShader。
© 2024 The Qt Company Ltd。本说明文档中包含的贡献归各自所有者享有版权。本说明文档按照自由软件基金会发布的 GNU 自由文档许可证版本 1.3 的条款进行许可。Qt 和相应标志是芬兰及/或其他国家的 The Qt Company Ltd. 的 商标。所有其他商标均为各自所有者的财产。