Qml 中用 Shader 实现圣诞树旋转灯

news2024/11/18 9:29:26

一、前言

        2022年圣诞节到来啦,很高兴这次我们又能一起度过~

        这次给大家带来一个简单漂亮圣诞树灯。

        当然了,本篇文章主要是讲解一下如何在 Qml 中使用 GLSL 来实现自己的特效。

        至于代码嘛,我比较喜欢在 Shaderjoy 上寻找,那里有很多超级炫酷的着色器实现的特效,并且可以很轻松的集成到 Qml 中。


二、纯 GLSL 实现的圣诞树旋转灯

        首先,想要在 Qml 中使用 GLSL,我们需要借助 ShaderEffect

ShaderEffect 类型将自定义顶点和片段(像素)着色器应用于矩形。它允许在 QML 场景中添加阴影、模糊、着色和页面卷曲等效果。
注意:根据使用的 Qt Quick Scenegraph 后端,可能不支持 ShaderEffect 类型。例如,使用软件后端,则根本不会渲染效果。

        ShaderEffect 有两个重要属性:

        vertexShader: 此属性保存顶点着色器源码字符串 ( 实际上也可以是文件 )。

        fragmentShader: 此属性保存片元着色器源码字符串 ( 实际上也可以是文件 )。

        我这里就比较简单了,直接将着色器代码文件传入即可:

import QtQuick 2.15
import QtQuick.Window 2.15

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"
        fragmentShader: "file:./glsl/christmas_tree_lights.frag"
        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;
        }
    }
}

        当然,还要向着色器中传入一些 uniform 变量,直接在 Qml 中声明即可,Qt 会自动帮我们传入。

        着色器的代码来自 Shadertoy:https://www.shadertoy.com

        顶点着色器很简单,直接传递变量,计算顶点即可:

#version 450

uniform mat4 qt_Matrix;
in vec4 qt_Vertex;
out vec4 fragCoord;

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

        然后是片元着色器( 比较复杂 ) :

#version 450

in vec4 fragCoord;

uniform vec3 iResolution; // viewport resolution (in pixels)
uniform 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(void)
{
    mainImage(gl_FragColor, vec2(fragCoord.x, iResolution.y - fragCoord.y));
}

三、效果展示

        _(:3 」∠)_  动图质量不太行,大家凑合看。


四、结语

        另外,要提一点:

在Qt 5中,效果以GLSL(OpenGL着色语言)源代码的形式提供,通常作为字符串嵌入QML中。从Qt 5.8开始,可以引用本地文件或Qt资源系统中的文件。
在Qt 6中,Qt Quick支持图形API,如Vulkan、Metal和Direct3D 11。因此,使用GLSL源字符串不再可行。相反,新的着色器管道基于将Vulkan兼容的GLSL代码编译成SPIR-V,然后收集反射信息并翻译成其他着色语言,如HLSL、金属着色语言和各种GLSL版本。生成的资产被打包到一个单独的包中,通常存储在扩展名为.qsb的文件中。此过程最迟在应用程序构建时离线完成。在运行时,场景图和底层图形抽象使用这些.qsb文件。因此,ShaderEffect需要Qt 6中的文件(本地或qrc)引用来代替内联着色器代码。
例如,vertexShader和fragmentShader属性是Qt 6中的URL,其工作方式与Image.source非常相似。然而,ShaderEffect仅支持文件和qrc方案。也可以省略文件方案,以便以方便的方式指定相对路径。这样的路径是相对于组件(.qml文件)位置解析的。

         因此,在 Qt 6 中,我们可以使用更加广泛的 qsb,这样只需要写一种着色器即可支持所有后端。

        不过关于 qsb 具体如何使用,我后面会写一下相关的博客~


五、源码下载

        Github的:

https://github.com/mengps/ShadertoyExampleshttps://github.com/mengps/ShadertoyExamples        CSDN的:

https://download.csdn.net/download/u011283226/87342581https://download.csdn.net/download/u011283226/87342581

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

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

相关文章

Biotin-PEG-Biotin,生物素-聚乙二醇-生物素聚乙二醇试剂供应

一&#xff1a;产品描述 1、名称 英文&#xff1a;Biotin-PEG-Biotin 中文&#xff1a;生物素-聚乙二醇-生物素 2、CAS编号&#xff1a;N/A 3、所属分类&#xff1a;Biotin PEG 4、分子量&#xff1a;可定制&#xff0c;2000/10000/3400/1000/20000/500 5、质量控制&…

c++继承知识点

目录1.继承的概念及定义1.1继承的概念1.2 继承定义1.2.1定义格式1.2.2继承关系和访问限定符1.2.3继承基类成员访问方式的变化2.基类和派生类对象赋值转换3.继承中的作用域4.派生类的默认成员函数5.继承与友元6. 继承与静态成员如何定义一个不被继承的类7.继承的一个题目8. 复杂…

目标检测之YOLOv2算法分析

要点 Batch Normalization 训练 若batchsize64,某一层的某一个神经元会输出64个响应值&#xff0c;对这64个响应值求均值&#xff0c;标准差&#xff0c;然后标准化&#xff0c;对标准化的结果乘λβ\lambda \betaλβ,其中λ\lambdaλ和 β\betaβ是需要训练的参数&#xf…

Windows平台RTMP、RTSP播放器录像模块精细化控制

技术背景 上篇文章&#xff0c;我们介绍了Unity平台RTMP、RTSP播放器录像功能&#xff0c;这里&#xff0c;我们详细的介绍下&#xff0c;做个RTSP或RTMP拉流端录像模块有哪些需要考虑的技术点&#xff1f; 在我们常规的考量&#xff0c;RTMP或RTSP流录制&#xff0c;无非就是…

在gitee上新建仓库并上传文件

一、进入到自己gitee的个人主页&#xff0c;点击图示新建仓库 二、根据图示操作&#xff0c;最后点击创建 三、如果没有配置git全局设置&#xff0c;需要配置一下(配置过的可以跳过这一步) 四、打开你要上传的文件&#xff0c;在里面右击鼠标&#xff0c;点击如图所示 五、输入…

spring之Bean的循环依赖问题

文章目录一、Bean的循环依赖之Set注入模式下1、Husband类2、Wife类3、Spring配置文件4、测试类5、测试结果6、结论二、Bean的循环依赖之构造方法注入模式下1、Husband类2、Wife类3、Spring配置文件4、测试类5、运行结果三、Spring解决循环依赖的机理三级缓存&#xff08;面试常…

PyQt5 基本布局管理 及 信号槽机制

一&#xff1a;布局设计 & 信号槽机制 效果实现如下&#xff1a; 对于窗口整体设计左右布局 对于左边布局&#xff0c;包括有水平布局(用户信息 左上方一块)垂直布局(多个按钮 左下方一块) 对于右边布局&#xff0c;主要是窗口切换&#xff0c;通过按下左边布局的左下方侧按…

SQLAlchemy连接MySQL及记录的查询、更新、删除、多表关联查询

SQLAlchemy是Python的ORM库&#xff0c;支持多种数据库。 建立连接 连接MySQL要用到Engine&#xff0c;Engine集成了连接池pool和方言Dialect&#xff08;支持不通数据库的SQL语法&#xff09;&#xff0c;最后都统一成标准DBAPI。 from sqlalchemy import create_engine en…

TypeScript

现在说起TypeScript想必大家都不会陌生的&#xff0c;当初从碎片信息中了解TypeScript&#xff0c;我认为他的变量声明和Rust语言有几分相似&#xff0c;是一门比较严格的语言&#xff0c;今天正式的来学习他 JavaScript易学习&#xff0c;易用&#xff0c;以至于大多数人对于…

软件体系结构 思维导图

软件体系结构 思维导图 软件体系结构思维导图 源文件放在 GitHub 仓库 使用 Xmind 即可打开查看 课程评价 比较抽象和理论化&#xff0c;如果光看 PPT 肯定看不懂&#xff0c;得听课或者看视频 后面实验试图基于 SpringBoot 去实战教学&#xff0c;可惜没系统学过只能照搬…

Kafka Consumer开发

Kafka Consumer - 消费者 跟生产者一样&#xff0c;消费者也属于kafka的客户端&#xff0c;不过kafka消费者是从kafka读取数据的应用&#xff0c;侧重于读数据。一个或多个消费者订阅kafka集群中的topic&#xff0c;并从broker接收topic消息&#xff0c;从而进行业务处理。今天…

一种嵌入式项目的参数保存方案

设计背景 嵌入式项目中&#xff0c;为了保证系统的正常运转&#xff0c;通常需要保存一部分数据至非易失存储设备如flash中。此处提供了一种通用的方案用于快速在项目中集成参数保存功能&#xff0c;该方案有以下几点特征&#xff1a; 接口简便&#xff0c;方便快速集成以及使用…

东北大学2023分布式操作系统实验

1.实验目的 建立伪分布式&#xff08;有条件的可以建立分布式环境&#xff09;的Hadoop环境&#xff0c;并成功运行示例程序。 2.Hadoop简介 2.1 Hadoop项目基础结构 在其核心&#xff0c;Hadoop主要有两个层次&#xff0c;即&#xff1a; 加工/计算层(MapReduce)存储层(Ha…

Python pandas有几千个库函数,你用过几个?(1)

对Python的 pandas 库所有的内置元类、函数、子模块等全部浏览一遍&#xff0c;然后挑选一些重点学习一下。我安装的库版本号为1.3.5&#xff0c;如下&#xff1a; >>> import pandas as pd >>> pd.__version__ 1.3.5 >>> print(pd.__doc__)pandas…

C++ STL vector list set map容器循环通过迭代器删除元素注意事项

先说说写这篇博客的原因吧&#xff0c;同事转部门了&#xff0c;把他手头的工作交接给了我。他以前维护的一个模块&#xff0c;会将外部输入的数据缓存起来分段处理&#xff0c;处理完了就会清除缓存数据&#xff0c;最近出现了一个bug&#xff0c;缓存数据一直不清除&#xff…

【SpringMVC】非注解的处理器映射器和适配器

项目目录 1.导入的依赖 pom.xml <properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target><…

【K3s】第2篇 一篇文章学习实践K3s部署安装

目录 1、docker安装 2、docker-compose安装 3、K3s安装 3.1 k3s与install.sh文件准备 3.2 k3s 安装步骤 4、查看k3s部署状态 1、docker安装 方式一 https://fanjufei.blog.csdn.net/article/details/123500511https://fanjufei.blog.csdn.net/article/details/123500511 …

12.24

接口测试 ​ <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-width…

Unity3D异步加载场景SceneManager.LoadSceneAsync()卡住,并不异步,获取process直接到0.9的问题

问题阐述&#xff1a; 一般来说&#xff0c;在加载场景的时候&#xff0c;会因为所加载资源的大小、复杂度、电脑配置等因素导致加载过程耗费一定的时间。虽然这个加载时间是不可避免的&#xff0c;但是在这一小段卡着的时间里如果就这样卡着的话会大大降低玩家体验。 所以很多…

(matlab编程基础)数组的基本操作

目录 1、数组寻址 2、数组元素删除 3、数组查找和排序 &#xff08;1&#xff09;数组查找 &#xff08;2&#xff09;数组排序 4、数组运算 5、数组操作函数 数组操作主要从以下5部分进行介绍:数组寻址、数组元素的删除、数组查找和排序、数组运算和数组操作函数。 1、…