Qt6 中如何使用 qsb

news2024/11/19 14:42:24

【写在前面】

        Qt 5 的图形体系结构非常依赖 OpenGL 作为底层 3D 图形 API。但过去 8 年来随着 Metal 和 Vulkan 的推出,市场发生了巨大变化。现在,Qt 6 加入了大量不同平台的图形 API,以确保用户可以在所有平台上以最高性能运行 Qt。

        在 Qt Quick 中的所有 3D 图形现在都基于称为 RHI(渲染硬件接口)的 3D 图形新抽象层之上。RHI 使 Qt 可以使用基础 OS /平台的本机 3D 图形 API。因此,默认情况下,Qt Quick 现在将在 Windows 上使用Direct3D,在 macOS 上使用 Metal。有关详细信息,请参阅有关 RHI 的博客文章系列。 

        Qt 中的 OpenGL 特定类仍然存在,但现在已从 QtOpenGL 模块中的 QtGui 中移出。此外,Qt 6 还添加了一个名为 QtShaderTools ( Qt 着色器工具 ) 的新模块,以跨平台的方式处理这些 API 的不同着色语言。


【qsb详细说明】

        qsb 是 Qt 着色器工具模块提供的命令行工具。

        它集成了第三方库,如 glsland SPIRV-Cross,可以选择调用外部工具,如 fxc 或 SPIRV-opt,并生成 .qsb 文件。此外,它还可用于检查 .qsb 包的内容。

简单提一下:

        glsland 是用于将 GLSL 转换为 SPIR-V 的工具。

        SPIRV-Cross 是用于将 SPIR-V 解析和转换为其他着色器语言的工具。

        Qt 着色器工具模块构建在 Khronos SPIR-V 网站上描述的 SPIR-V 开源生态系统上。为了编译成 SPIR-V,使用 glsland,而翻译和反射是通过 SPIRV-Cross 完成的。

        为了允许在 Qt 应用程序和库中编写一次着色器代码,所有着色器都应该用一种语言编写,然后编译成SPIR-V。目前,这种 shanding 语言是与 Vulkan 兼容的 GLSL。这与 OpenGL 风格 GLSL Qt 5.x 预期的不同。有关差异的概述,请参阅 GL_KHR_vulkan_glsl 规范。

        然后通过翻译 SPIR-V 字节码以及反射信息(输入、输出、着色器资源)生成其他着色语言(如 GLSL、HLSL 和金属着色语言)的源代码。

        特别是对于 GLSL,这还涉及生成多个变体,这意味着源代码适用于不同的 GLSL 版本,例如 GLSL ES 100、GLSL ES 300、GLSL 120、150等。然后将所有这些都打包到可序列化的 QShader 容器对象中,通常以扩展名为 .qsb 的文件形式存储在磁盘中。

        Qt 渲染硬件接口( RHI )直接使用 QShader 实例,选择最适合运行时使用的图形 API 的着色器源或字节码。QShader 对象通常从应用程序附带的 .qsb 文件或 Qt 资源系统中的Qt本身反序列化。

        一些平台提供了将着色器源代码编译为类似于 SPIR-V 的中间格式的选项。这涉及运行特定于平台的工具。使用 Direct 3D,qsb 工具提供了在生成 HLSL 源代码后从 Windows SDK 调用 fxc 工具的选项。

        然后,它用 fxc 生成的 DXBC 二进制文件替换 HLSL 源代码。这可以对应用程序的运行时性能产生积极影响,因为它们不再需要自己进行第一阶段的编译( HLSL 源代码到 DXBC )。对于 macOS 和 iOS,XCode SDK 提供了类似的工具。这种方法的缺点是,只能在各自的平台上运行这些工具。

        因此,这最适合与 qsb 的 CMake 集成结合使用,因为在应用程序构建时进行着色器调节隐含地提供了有关目标平台以及可以调用哪些平台特定工具的知识。

        下图描述了调用 qsb 工具期间发生的步骤:

        Qt 着色器调节系统的主要组件包括:

        - qsb命令行工具

        - CMake集成qsb工具

        - QShader(QtGui模块的一部分)

        - QShaderBaker(本模块的一部分,与 qsb 工具等效的库)

        注意:从 Qt 6.2 开始,C++API 被认为是私有的。不建议从应用程序直接使用它们。相反,直接或间接从 CMake 项目使用 qsb 命令行工具。


【正文开始】

        上面巴拉巴拉讲了一大坨,我们不需要过于关心,只需要知道:Qt 6 以后,对于 Qt Quick 不再直接使用各个图形 API 的着色器语言,而是使用一种 .qsb 的文件,这个文件由 qsb.exe 工具生成,它包含了各个图形 API 使用的字节码。

        通过使用 qsb,我们便可以自由切换硬件渲染后端而无需写多个平台的着色器代码。

        另一方面,.qsb 文件主要由 Qt Scene Graph Qt3D 使用,当然,Qml 中相关的组件也同样使用,例如:ShaderEffect

        因此,本篇使用前一篇的圣诞树作为例子来教大家如何使用。

        首先,因为现在是 Qt6,所以需要使用 qsb.exe glsl 文件生成 .qsb 文件:

        qsb.exe 工具的位置位于编译套件目录下的 bin 文件夹中,比如 Qt\6.2.0\msvc2019_64\bin,接着,我们敲入命令:

qsb.exe --glsl "450 es,120,150" --hlsl 50 --msl 12 -o christmas_tree_lights.vert.qsb .\christmas_tree_lights.vert

qsb.exe --glsl "450 es,120,150" --hlsl 50 --msl 12 -o christmas_tree_lights.frag.qsb .\christmas_tree_lights.frag

        将分别生成 christmas_tree_lights.vert.qsb 和 christmas_tree_lights.frag.qsb,这是顶点&片段着色器对应的各个平台着色器的字节码。

        命令具体的意义很简单,也可以使用 qsb --help 来获取帮助、

        接着,上篇 ShaderEffect vertexShader fragmentShader 文件名需要更改:

import QtQuick
import QtQuick.Window

Window {
    id: root
    width: 1280
    height: 900
    visible: true
    title: qsTr("Christmas tree lights")

    ShaderEffect {
        anchors.fill: parent
        vertexShader: "file:./glsl/christmas_tree_lights.vert.qsb"
        fragmentShader: "file:./glsl/christmas_tree_lights.frag.qsb"
        property vector3d iResolution: Qt.vector3d(root.width, root.height, 0)
        property real iTime: 0

        Text {
            text: "Time: " + parent.iTime.toFixed(2)
            color: "white"
        }

        Timer {
            running: true
            repeat: true
            interval: 10
            onTriggered: parent.iTime += 0.01;
        }
    }
}

        导入 qsb 即可。

        当然,要生成 qsb,我们的 glsl 需要改为 GL_KHR_vulkan_glsl,其规范链接:GLSL/GL_KHR_vulkan_glsl.txt at master · KhronosGroup/GLSL · GitHubGLSL Shading Language Issue Tracker. Contribute to KhronosGroup/GLSL development by creating an account on GitHub.https://github.com/KhronosGroup/GLSL/blob/master/extensions/khr/GL_KHR_vulkan_glsl.txt        顶点着色器 christmas_tree_lights.vert 改为:

#version 450

layout(location = 0) in vec4 qt_Vertex;
layout(location = 1) in vec2 qt_MultiTexCoord0; //未使用
layout(location = 0) out vec4 fragCoord;
layout(std140, binding = 0) uniform buf {
    mat4 qt_Matrix;
};

void main()
{
    fragCoord = qt_Vertex;
    gl_Position = qt_Matrix * qt_Vertex;
}

        因为 ShaderEffect 有一些默认的输入,即便没有使用也需要写全。

        片段着色器 christmas_tree_lights.frag 改为:

#version 450

layout(location = 0) in vec2 fragCoord;
layout(location = 0) out vec4 fragColor;
layout(std140, binding = 0) uniform buf {
    mat4 qt_Matrix;
    float qt_Opacity;
    vec3 iResolution; // viewport resolution (in pixels)
    float iTime;      // shader playback time (in seconds)
};

const float pi = 3.1415927;
const float dotsnbt = 90.0; // Number of dots for the tree
const float dotsnbs = 20.0; // Number of dots for the star (per circle)

vec3 hsv2rgb (vec3 hsv) { // from HSV to RGB color vector
    hsv.yz = clamp (hsv.yz, 0.0, 1.0);
    return hsv.z * (1.0 + 0.63 * hsv.y * (cos (2.0 * 3.14159 * (hsv.x + vec3 (0.0, 2.0 / 3.0, 1.0 / 3.0))) - 1.0));
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    float time = iTime;
    float mx = max(iResolution.x, iResolution.y);
    vec2 scrs = iResolution.xy / mx;
    vec2 uv = vec2(fragCoord.x, iResolution.y - fragCoord.y) / mx;
    //vec2 m = vec2(mouse.x / scrs.x, mouse.y * (scrs.y / scrs.x));

    vec2 pos = vec2(0.0);               // Position of the dots
    vec3 col = vec3(0.0);               // Color of the dots
    float intensitys = 1.0 / 4000.0;    // Light intensity for the star
    float intensityt = 1.0 / 2000.0;    // Light intensity for the tree
    float scale = 0.2;                  // Size of the star

    /*** Star ***/
    for(float i = 0.0 ; i < dotsnbs; i++){
        pos = vec2(cos(time * 0.2) / 20.0 * cos(2.0 * pi * i / dotsnbs),
                   0.15 * sin(2.0 * pi * i / dotsnbs)) * scale;
        pos += vec2(scrs.x / 2.0, scrs.y * 0.11);

        col += hsv2rgb(vec3(i / dotsnbs, distance(uv, pos) * (1.0 / intensitys), intensitys / distance(uv, pos)));

        pos = vec2(0.12 * cos(2.0 * pi * i / dotsnbs + time * 0.2),
                   0.08 * sin(2.0 * pi * i / dotsnbs)) * scale;
        pos += vec2(scrs.x / 2.0, scrs.y * 0.11);

        col += hsv2rgb(vec3(1.0 - i / dotsnbs, distance(uv, pos) * (1.0 / intensitys), intensitys / distance(uv, pos)));

        pos = vec2(0.12 * cos(2.0 * pi * i / dotsnbs + time * 0.2),
                   -0.08 * sin(2.0 * pi * i / dotsnbs)) * scale;
        pos += vec2(scrs.x / 2.0, scrs.y * 0.11);

        col += hsv2rgb(vec3(i / dotsnbs, distance(uv, pos) * (1.0 / intensitys), intensitys / distance(uv, pos)));
    }

    /*** Tree ***/
    float angle = dotsnbt * 1.8; // Angle of the cone
    for(float i = 0.0 ; i < dotsnbt ; i++){
        pos = vec2(scrs.x / 2.0 + sin(i / 2.0 - time * 0.2) / (3.0 / (i + 1.0) * angle),
                   scrs.y * ((i) / dotsnbt + 0.21) * 0.80);

        col += hsv2rgb(vec3(1.5 * i / dotsnbt + fract(time / 4.0), distance(uv, pos) * (1.0 / intensityt), intensityt / distance(uv, pos)));
    }

    fragColor = vec4( col, 1.0 );
}

void main() {
    mainImage(fragColor, vec2(fragCoord.x, iResolution.y - fragCoord.y));
}

        运行的效果与前篇一致:


【结语】

        最后,如果需要完整代码或者了解 ShaderEffect 的用法,可以看看前篇:

Qml 中用 Shader 实现圣诞树旋转灯_梦起丶的博客-CSDN博客2022年圣诞节到来啦,很高兴这次我们又能一起度过~这次给大家带来一个简单漂亮圣诞树灯。当然了,本篇文章主要是讲解一下如何在 Qml 中使用GLSL来实现自己的特效。至于代码嘛,我比较喜欢在Shaderjoy上寻找,那里有很多超级炫酷的着色器实现的特效,并且可以很轻松的集成到 Qml 中。https://blog.csdn.net/u011283226/article/details/128429822?spm=1001.2014.3001.5501

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/135586.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【类和对象(完结)】

目录 1. 再谈构造函数 1.1 构造函数体赋值 1.2 初始化列表 1.3 explicit关键字 2. static成员 2.1 概念 2.2 特性 3. 友元 3.1 友元函数 3.2 友元类 4. 内部类 5.匿名对象 6.拷贝对象时的一些编译器优化 7. 再次理解类和对象 8.总结 1. 再谈构造函数 1.1 构造函数体…

技术分享| 如何使用Prometheus实现系统进程监控

如何监控线上正在运营的系统&#xff1f;如何得知系统目前是正常还是异常&#xff1f; Prometheus是这么一套数据监控解决方案。它能让运维及开发人员随时掌控系统的运行状态&#xff0c;快速定位出现问题的位置&#xff0c;快速排除故障。只要按照 Prometheus的方式来做&#…

力扣刷题记录——258. 各位相加、263.丑数、268.丢失的数字

本专栏主要记录力扣的刷题记录&#xff0c;备战蓝桥杯&#xff0c;供复盘和优化算法使用&#xff0c;也希望给大家带来帮助&#xff0c;博主是算法小白&#xff0c;希望各位大佬不要见笑&#xff0c;今天要分享的是——《258. 各位相加、263.丑数、268.丢失的数字》。 目录 25…

第三十五讲:神州无线局域网基础知识

1. IEEE 802.11协议 802.11无线标准家族包括802.11a/b/g/n/ac五个标准理论上可以提供高达每秒1Gbit的数据传输能力标准定义了如何使用免授权2.4 GHz 和 5GHz 频带的电磁波进行信号传输。 802.11无线标准家族 802.11a 802.11b 802.11g 802.11n 802.11ac 工作频段 5GHz 2…

内存访问为什么要分段?

内存分段是处理器为访问内存而设计的机制&#xff0c;称为内存分段机制。 简单的内存知识 内存结构&#xff08;连续且地址依次升高&#xff09; 访问方式 内存是随机读写设备&#xff0c;即访问其内部任何处&#xff0c;不需要从头开始找&#xff0c;只要直接给出其地址便可。…

【项目启动】IDEA新建项目同步到Github

文章目录SSH秘钥检查GitHub创建项目IDEA创建项目IDEA同步GitHubSSH秘钥检查 目前&#xff0c;github不支持https形式的远程同步方式&#xff0c;如果使用https形式进行同步会报以下错误&#xff1a; remote: Support for password authentication was removed on August 13, 2…

C# WinForm CAD文件显示(dxf,dwg显示)

找遍全网很难找到开源dxf显示控件(C# winform)&#xff0c;大部分控件都需要收费&#xff0c;对于做软件开发很麻烦 C# WPF倒是有nefdxfZoomableCanvas可以实现&#xff0c;确实很方便&#xff0c;这个在github&#xff1a;https://github.com/shao200/WpfDxfViewer上也能找到开…

c++11 标准模板(STL)(std::deque)(六)

定义于头文件 <deque> std::deque 容量 检查容器是否为空 std::deque<T,Allocator>::empty bool empty() const; (C11 前) bool empty() const noexcept; (C11 起) (C20 前) [[nodiscard]] bool empty() const noexcept; (C20 起)检查容器是否无元素&#xff0c…

大数据NiFi(四):NiFi单节点安装

文章目录 NiFi单节点安装 一、介绍与下载 二、单节点安装

JavaWeb:JSP概述及原理

1&#xff0c;JSP概述 JSP&#xff08;全称&#xff1a;Java Server Pages&#xff09;&#xff1a;Java服务端页面。 是一种动态的网页技术&#xff0c;其中既可以定义 HTML、JS、CSS等静态内容&#xff0c;还可以定义 Java代码的动态内容&#xff0c;也就是 JSP HTML Java…

javaee之SpringMVC2

SpringMVC返回值类型以及响应数据类型 1.搭建环境 还是按照springMVC1中的搭建环境进行搭建。这里就不多说。 响应之返回值是String类型 我们先来创建一个User类 User,java package com.pxx.domain;import java.io.Serializable;public class User implements Serializab…

PS 矩形选区工具(1)基本用法 生成图层 选区方式演示讲解

我们先打开PS 然后打开一个项目 我们可以选择一个图层 然后 点击左上角 图像>调整>色相.饱和度 弹出操作框之后 我们拉动色相的色条 对应视图就会发生主体颜色的变化 然后 我们打开一个只有一个图层的图片项目 我们对这个图层操作 整个都会变化 但如果我只是想改其中…

后悔升级iPhone?教你如何把iOS15降回iOS14

还在使用betabeta版iOS 15和iPadOS 15吗&#xff1f;如果你出于某种原因准备返回稳定的iOS 14&#xff0c;本篇文章将会为你详细介绍如何从 iOS 15 beta版降级到 iOS 14&#xff0c;这对于有一定动手能力的人来说并不难。 如何从 iOS 15 beta版降级到 iOS 14 重要提示&#xf…

Spring是怎么回事?新手入门就看这篇吧

前言 今天壹哥给大家介绍一套开源的轻量级框架&#xff0c;它就是Spring。在给大家详细讲解Spring框架之前&#xff0c;壹哥先给大家介绍Spring框架的主要内容&#xff1a; Spring的基本概念 Spring核心思想之ioc Spring核心思想之aop Spring框架对事务的支持 在本系列文章…

解决前端如何使用插件crypto-js进行AES加密方式数据加密

一、问题 目录 一、问题 1.1 问题概述 1.2 操作过程描述 二、解决 2.1 说明 2.2 crypto-js安装 2.3 使用crypto-js 1.1 问题概述 如何进行加密和解密以及采用什么方式进行加密解密是本文主要解决的内容~ 之前有小伙伴问了关于加密解密的事&#xff0c;确实是的&#xff…

pdfbox / XSL + FOP 转换 PDF文档

XSL-FO是XSL Formatting Objects的缩写&#xff0c;它是一种用于文档格式的XML 置标语言。XSL-FO是XSL的一部分&#xff0c;而XSL是一组定义XML数据转换与格式的W3C技术。XSL的其他部分有XSLT与XPath。 XSL-FO是用于格式化XML数据的语言&#xff0c;全称为Extensible Styleshe…

python基础讲解 02

人工智能学习基础四剑客&#xff08;库&#xff09;Numpy ( Numerical Python)使用创建随机数组查看数组的属性数组与标量之间的计算四剑客&#xff08;库&#xff09; Python被大量应用在数据挖掘和深度学习领域,其中使用极其广泛的是Numpy&#xff08;N维数组对象和向量运算&…

Nessus学习

攻击主机&#xff1a; Kali 192.168.11.106靶机&#xff1a;windows server 2008 r2 192.168.11.134 x64 32位nessus实验原理&#xff1a;利用漏洞扫描器能够自动应用漏洞扫描原理&#xff0c;对目标主机安全漏洞进行检测&#xff0c;附带识别主机漏洞的特征库的功能&#xf…

使用客户端证书登录MySQL

使用客户端证书登录MySQL登录MySQL具有安全性高、不用输入密码的优点&#xff0c;这里说明生成证书和登录的过程。 实验环境是Linux上的的MySQL 8.0.31社区版。 生成证书 使用openssl req创建X.509证书&#xff0c;下面的命令创建有效期10年的私钥&#xff0c;使用man req可…

Kali Linux中shutdown指令的用法3-3

3 TIME介绍 TIME是shutdown指令的第二个参数&#xff0c;用来表示实现关机计划的时间&#xff0c;如果不指定TIME&#xff0c;则默认是1分钟之后实现关机计划。 3.1 通过hh:mm格式指定时间 可以通过hh:mm格式指定关机的具体时间&#xff0c;其中hh表示小时&#xff0c;mm表示…