ShaderEffect QML Type

对矩形应用自定义着色器。更多

Import Statement: import QtQuick
Inherits:

Item

属性

详细说明

ShaderEffect 类型将自定义的vertexfragment (pixel) 着色器应用于矩形。它允许在 QML 场景中添加阴影、模糊、着色和页面卷曲等效果。

注: 根据使用的Qt Quick 场景图后端,ShaderEffect 类型可能不受支持。例如,software 后端根本不会渲染特效。

着色器

在 Qt 5 中,特效以 GLSL(OpenGL 着色语言)源代码的形式提供,通常以字符串的形式嵌入 Qt 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)来代替内联着色器代码。

vertexShaderfragmentShader 属性是 Qt 6 中的 URL,其工作原理与Image.source 等非常相似。不过,ShaderEffect 只支持fileqrc 方案。也可以省略file 方案,以方便地指定相对路径。这样的路径会相对于组件(.qml 文件)的位置进行解析。

着色器输入和资源

vertexShader 有两种输入类型:制服输入和顶点输入。

以下是预定义的输入:

  • vec4 qt_Vertex,位置为 0 - 顶点位置,左上方顶点的位置为(0, 0),右下方顶点的位置为(width,height )。
  • vec2 qt_MultiTexCoord0,位置 1 - 纹理坐标,左上角坐标为(0, 0),右下角为(1, 1)。如果supportsAtlasTextures 为 true,坐标将基于图集中的位置。

注意: 实际上,顶点输入位置才是最重要的。名称可以自由更改,但顶点位置的位置必须始终为0 ,纹理坐标的位置必须始终为1 。但请注意,这只适用于顶点输入,而不一定适用于顶点着色器的输出变量,这些变量随后会被用作片段着色器的输入(通常是插值纹理坐标)。

以下是预定义的制服:

  • mat4 qt_Matrix - 组合变换矩阵,即从根项到此 ShaderEffect 的矩阵与正交投影的乘积。
  • float qt_Opacity - 综合不透明度,从根项目到此 ShaderEffect 的不透明度的乘积。

注意: Vulkan 风格的 GLSL 没有单独的统一变量。相反,着色器必须始终使用绑定点为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。要包含 fillMode,请使用 或 Image::layer::enabled。ShaderEffectSource
  • ShaderEffectSource -> sampler2D - 原点位于左上角,颜色值为预相乘值。

在着色器代码中,采样器仍被声明为单独的统一变量。着色器可以自由选择这些变量的任何绑定点,但0 除外,因为它是为统一块保留的。

有些着色语言和应用程序接口有独立图像和采样器对象的概念。Qt Quick 在着色器中始终使用组合图像采样器对象,SPIR-V 也支持这种做法。因此,为 ShaderEffect 提供的着色器应始终使用layout(binding = 1) uniform sampler2D tex; 样式的采样器声明。底层抽象层和着色器管道会为所有支持的应用程序接口和着色语言处理这些工作,对应用程序透明。

QML 场景图后端可选择在纹理图集中分配纹理。如果将在图集中分配的纹理传递给 ShaderEffect,默认情况下会将其从纹理图集中复制到独立纹理中,这样纹理坐标就会从 0 跨到 1,并获得预期的包模式。不过,这会增加内存使用量。要避免纹理复制,可使用 qt_MultiTexCoord0 为简单着色器设置supportsAtlasTextures ,或为每个 "统一采样器 2D <名称>"声明一个 "统一 vc4 qt_SubRect_<名称>",它将被分配给纹理的归一化源矩形。对于独立的纹理,源矩形为 [0, 1]x[0, 1]。对于图集中的纹理,源矩形对应于纹理图集中存储纹理的部分。计算纹理图集中名为 "source "的纹理坐标的正确方法是 "qt_SubRect_source.xy + qt_SubRect_source.zw * qt_MultiTexCoord0"。

fragmentShader 的输出应预先相乘。如果启用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.vertmyeffect.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 中常见的左下角。

只有一个着色器

并非必须同时指定vertexShaderfragmentShader 。许多 ShaderEffect 实现在实践中只想提供片段着色器,而依赖于默认的内置顶点着色器。

默认的顶点着色器会将纹理坐标以vec2 qt_TexCoord0 的形式传递给片段着色器,位置为0

默认片段着色器希望将纹理坐标从顶点着色器传递到vec2 qt_TexCoord0 (位置:0 ),并从名为source 的采样器 2D 中采样(绑定点:1 )。

警告: 当只指定了其中一个着色器时,着色器的编写者必须了解默认着色器所期望的统一块布局:qt_Matrix 必须始终位于偏移 0 处,qt_Opacity 位于偏移 64 处。任何自定义统一块都必须放在这两个位置之后。即使应用程序提供的着色器不使用矩阵或不透明度,这也是必须的,因为在运行时,顶点和片段着色器都会看到一个单一的统一缓冲区。

警告 与顶点输入不同,顶点着色器和片段着色器之间的数据传递可能需要使用相同的名称,这取决于底层图形 API,但匹配的位置并不总是足够的。最明显的是,在依赖默认内置顶点着色器指定片段着色器时,纹理坐标会以qt_TexCoord0 的形式传递到0 位置,因此强烈建议片段着色器使用相同的名称(qt_TexCoord0)声明输入。如果不这样做,在某些平台上可能会出现问题,例如在非核心配置文件 OpenGL 上下文中运行时,底层 GLSL 着色器源代码没有位置限定符,而匹配是基于着色器链接过程中的变量名。

着色器效果和项目层

ShaderEffect 类型可与layered items.图层结合使用。

禁用效果的图层 启用效果的图层
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 移植

对于使用 ShaderEffect 项目的 Qt 5 应用程序,向 Qt 6 的迁移包括

  • 将着色器代码移至单独的.vert.frag 文件、
  • 将着色器更新为兼容 Vulkan 的 GLSL、
  • 在这些文件上运行qsb 工具、
  • 将生成的.qsb 文件包含在带有 Qt 资源系统的可执行文件中、
  • 并在vertexShaderfragmentShader 属性中引用该文件。

正如QtShader Tools模块中所述,其中一些步骤可以通过让 CMake 在构建时调用qsb 工具来自动完成。更多信息和示例请参见Qt XMLShader Tools Build System Integration

在更新着色器代码时,下面概述了通常需要进行的修改。

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 指令应说明440450 ,不过指定其他 GLSL 版本也可以,因为GL_KHR_vulkan_glsl扩展是为 GLSL 140 及更高版本编写的。
  • 输入和输出必须使用现代 GLSLinout 关键字。此外,还需要指定位置。输入和输出位置命名空间是分开的,因此为两者指定从 0 开始的位置是安全的。
  • 在顶点着色器输入方面,ShaderEffect 的唯一可能性是用于顶点位置的位置0 (传统名称为qt_Vertex )和用于纹理坐标的位置1 (传统名称为qt_MultiTexCoord0 )。
  • 顶点着色器输出和片段着色器输入由着色器代码定义。片段着色器必须在位置 0(通常称为fragColor )有一个vec4 输出。为获得最大的可移植性,顶点输出和片段输入应使用相同的位置编号和名称。仅指定片段着色器时,纹理坐标将从内置顶点着色器传入vec2 qt_TexCoord0 ,位置为0 ,如上例片段所示。
  • 统一块外的统一变量是不合法的。统一数据必须在绑定点为0 的统一块中声明。
  • 统一数据块应使用 std140 限定符。
  • 在运行时,顶点着色器和片段着色器将获得绑定到绑定点 0 的相同统一缓冲区。 因此,一般来说,着色器之间的统一块声明必须相同。这也包括未在其中一个着色器中使用的成员。成员名称必须一致,因为某些图形应用程序接口会将 uniform 块转换为传统的 struct uniform,这对应用程序来说是透明的。
  • 当只提供其中一个着色器时,请注意内置着色器希望qt_Matrixqt_Opacity 位于 uniform 块的顶部。(更准确地说,是分别位于偏移量 0 和 64 处)。一般情况下,应始终将这两个元素作为块中的第一个和第二个成员。
  • 在示例中,统一代码块指定的代码块名称为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 开始的绑定点。
  • Qt Quick 在启用multiview 的情况下进行渲染时,例如,由于它是 VR/AR 环境中 3D 场景渲染的一部分,左右眼的内容是一次性生成的,因此在编写 ShaderEffect 着色器时必须考虑到这一点。以视图数为 2 的情况为例,将有2 个矩阵(qt_Matrix 是一个包含两个元素的 mat4 数组)。顶点着色器应将gl_ViewIndex 考虑在内。有关创建多视图着色器的一般信息,请参见《QSB 手册》中的Multiview 部分。

另请参见 Item Layers《QSB 手册》Qt XMLShader Tools Build System Integration

属性文档

blending : bool

如果该属性为 true,则fragmentShader 的输出将使用源过混合模式与背景混合。如果为 false,则不考虑背景。混合会降低性能,因此在不需要混合时应将此属性设置为 false。默认值为 true。


cullMode : enumeration

该属性定义了项目的哪些面应该可见。

常数说明
ShaderEffect.NoCulling两侧都可见
ShaderEffect.BackFaceCulling仅正面可见
ShaderEffect.FrontFaceCulling仅背面可见

默认为 NoCulling。


fragmentShader : url

该属性包含对预处理片段着色器包文件的引用,扩展名通常为.qsb 。该值被视为URL ,与其他 QML 类型(如 Image)类似。它必须是本地文件,或使用 qrc 方案访问通过 Qt 资源系统嵌入的文件。URL 可以是绝对的,也可以是相对于组件 URL 的。

警告: 着色器(包括.qsb 文件)被假定为可信内容。建议应用程序开发人员在允许加载非应用程序一部分的用户提供内容之前,仔细考虑其潜在影响。

另请参阅 vertexShader


log : string [read-only]

此属性包含最近一次尝试编译着色器时出现的警告和错误日志。status 设置为编译或错误时,它也会同时更新。

注意: 在 Qt 6 中,着色器流水线提倡离线编译和翻译 Vulkan 风格的 GLSL 着色器,或最迟在构建时编译和翻译。这并不一定意味着在运行时不会进行着色器编译,但即使进行了编译,ShaderEffect 也不会参与其中,而且在这一阶段应该不会再出现语法和类似错误。因此,该属性的值通常为空。

另请参见 status


mesh : variant

该属性定义了用于绘制ShaderEffect 的网格。它可以包含任何GridMesh 对象。如果为该属性分配了尺寸值,ShaderEffect 将隐式使用该值的GridMesh 作为mesh resolution 。默认情况下,该属性的大小为 1x1。

另请参阅 GridMesh


status : enumeration [read-only]

该属性显示着色器的当前状态。

常量说明
ShaderEffect.Compiled着色器程序已成功编译并链接。
ShaderEffect.Uncompiled着色器程序尚未编译。
ShaderEffect.Error着色器程序编译或链接失败。

设置片段或顶点着色器源代码时,状态将变为未编译。首次使用新着色器源代码渲染ShaderEffect 时,着色器会被编译和链接,状态也会更新为已编译或错误。

当未使用运行时编译,且着色器属性指向包含字节码的文件时,状态始终为编译。着色器的内容直到渲染流水线的后期才会被检查(除了发现顶点输入元素和常量缓冲区数据的基本反射外),因此潜在的错误(如布局或根签名不匹配)只能在后期才会被发现。

另请参阅 log


supportsAtlasTextures : bool [since QtQuick 2.4]

设置此属性为 true 可确认着色器代码不依赖于 qt_MultiTexCoord0 相对于网格的范围从 (0,0) 到 (1,1)。在这种情况下,qt_MultiTexCoord0 的范围将基于纹理在图集中的位置。如果用于着色器输入的采样均匀度少于或多于一个,此属性目前不会产生任何影响。

这与提供 qt_SubRect_<name> 统一的不同之处在于,后者允许在单个ShaderEffect 项目中从图集中绘制一种或多种纹理,而 supportsAtlasTextures 则允许在单次绘制中批量绘制使用图集中不同源图像的ShaderEffect 组件的多个实例。当ShaderEffect 引用纹理时,两者都能防止纹理被从图集中复制出来。

默认值为 false。

该属性在 QtQuick 2.4 中引入。


vertexShader : url

该属性包含对预处理顶点着色器包文件的引用,通常扩展名为.qsb 。该值被视为URL ,与其他 QML 类型(如 Image)类似。它必须是本地文件,或使用 qrc 方案访问通过 Qt 资源系统嵌入的文件。URL 可以是绝对的,也可以是相对于组件 URL 的。

警告: 着色器(包括.qsb 文件)被假定为可信内容。建议应用程序开发人员在允许加载非应用程序一部分的用户提供内容之前,仔细考虑其潜在影响。

另请参阅 fragmentShader


© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.