QT+OpenGL高级数据和高级GLSL

news2024/10/7 8:27:01

QT+OpenGL高级数据和高级GLSL

本篇完整工程见gitee:QtOpenGL 对应点的tag,由turbolove提供技术支持,您可以关注博主或者私信博主

高级数据

  • OpenGL中的缓冲区 对象管理特定的GPU内存

  • 在将缓冲区绑定到特定的缓冲区目标时候赋予它意义

  • OpenGL在内部会保存每个目标(缓冲区)的引用,并且根据目标以不同的方式处理缓冲区。

glBufferData 填充缓冲对象所管理的内存

glBufferSubData 填充缓冲的特定区域

glBufferSubData(GL_ARRAY_BUFFER, 24, sizeof(data), &data);

将数据导入缓冲区的另外一种方法:

  • 通过调用glMapBuffer函数,OpenGL会返回当前绑定的缓冲区的内存指针
  • 直接将数据复制到缓冲中 glMapBuffer使用的时候,缓冲区的内存必须已经存在
float data[] = {
  0.5f, 1.0f, -0.35f
  ...
};
glBindBuffer(GL_ARRAY_BUFFER, buffer);
// 获取指针
void *ptr = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
// 复制数据到内存
memcpy(ptr, data, sizeof(data));
// 记得告诉OpenGL我们不再需要这个指针了
glUnmapBuffer(GL_ARRAY_BUFFER);

分批顶点属性

float positions[] = { ... };
float normals[] = { ... };
float tex[] = { ... };
// 填充缓冲
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(positions), &positions);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(positions), sizeof(normals), &normals);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(positions) + sizeof(normals), sizeof(tex), &tex);

使用glVertexAttribPointer,指定顶点数组缓冲区内筒的属性布局。

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);  
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)(sizeof(positions)));  
glVertexAttribPointer(
  2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)(sizeof(positions) + sizeof(normals)));

复制缓冲

当你的缓冲已经填充好数据之后,你可能会想与其它的缓冲共享其中的数据,或者想要将缓冲的内容复制到另一个缓冲当中。glCopyBufferSubData能够让我们相对容易地从一个缓冲中复制数据到另一个缓冲中。这个函数的原型如下:

void glCopyBufferSubData(GLenum readtarget, GLenum writetarget, GLintptr readoffset,
                         GLintptr writeoffset, GLsizeiptr size);

readtargetwritetarget参数需要填入复制源和复制目标的缓冲目标

如果想读写数据的两个不同缓冲都为顶点数组缓冲该怎么办?使用下面的例子:

float vertexData[] = { ... };
glBindBuffer(GL_COPY_READ_BUFFER, vbo1);
glBindBuffer(GL_COPY_WRITE_BUFFER, vbo2);
glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, sizeof(vertexData));
float vertexData[] = { ... };
glBindBuffer(GL_COPY_READ_BUFFER, vbo1);
glBindBuffer(GL_COPY_WRITE_BUFFER, vbo2);
glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, sizeof(vertexData));

高级GLSL

顶点着色器变量

  • gl_Position : 输出变量,顶点着色器的裁减空间位置向量
  • gl_PointSize :输出变量,是一个float变量,设置点的宽高(像素)
glEnable(GL_PROGRAM_POINT_SIZE); 
  • gl_VertexID :输入变量,储存了正在绘制顶点的当前ID

shader.vert

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;
out vec3 Normal;
out vec3 FragPos;
out vec2 TexCoords;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main() 
{
	TexCoords=aTexCoords;
	Normal = mat3(transpose(inverse(model))) * aNormal;
	FragPos=vec3(model * vec4(aPos,1.0));
	gl_Position = projection * view * model * vec4(aPos, 1.0);
	gl_PointSize = gl_Position.z;
}

在这里插入图片描述

片段着色器变量

  • gl_FragCoord :的x和y分量是片段的窗口空间的坐标,其原点为窗口的左下角,z分量等于对应片段的深度值
  • gl_FrontFacing :变量是一个bool如果当前片段是正面向的一部分那么就是true, 否则就是false
  • gl_FragDepth : 着色器内设置片段的深度值

shader.frag

void main() {
    if(gl_FragCoord.x < 400 )
        FragColor = vec4(1.0, 0.0, 0.0, 1.0);
    else
        FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}

在这里插入图片描述

gl_FrontFacing :变量是一个bool如果当前片段是正面向的一部分那么就是true, 否则就是false

#version 330 core
out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D frontTexture;
uniform sampler2D backTexture;
void main()
{             
    if(gl_FrontFacing)
        FragColor = texture(frontTexture, TexCoords);
    else
        FragColor = texture(backTexture, TexCoords);
}

gl_FragDepth : 着色器内设置片段的深度值

#version 420 core // 注意GLSL的版本!
out vec4 FragColor;
layout (depth_greater) out float gl_FragDepth;

void main()
{             
    FragColor = vec4(1.0);
    gl_FragDepth = gl_FragCoord.z + 0.1;
}  

layout (depth_<condition>) out float gl_FragDepth;

condition可以为下面的值:

条件描述
any默认值。提前深度测试是禁用的,你会损失很多性能
greater你只能让深度值比gl_FragCoord.z更大
less你只能让深度值比gl_FragCoord.z更小
unchanged如果你要写入gl_FragDepth,你将只能写入gl_FragCoord.z的值

接口块

接口块的声明和struct的声明有点相像,不同的是,现在根据它是一个输入还是输出块(Block),使用in或者out关键字来定义的。

shader.vert

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoords;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

out VS_OUT
{
    vec2 TexCoords;
} vs_out;

void main()
{
    gl_Position = projection * view * model * vec4(aPos, 1.0);    
    vs_out.TexCoords = aTexCoords;
}  

shader.frag

#version 330 core
out vec4 FragColor;

in VS_OUT
{
    vec2 TexCoords;
} fs_in;

uniform sampler2D texture;

void main()
{             
    FragColor = texture(texture, fs_in.TexCoords);   
}

只要两个接口块的名字一样,对应的输入和输出将会匹配起来。

块名应该是和着色器中一样的(VS_OUT)但是实例名称(vs_out, fs_in)是可以随意的。

Uniform缓冲对象

当使用多于一个的着色器时候,尽管大部分的uniform变量都是相同的,我们还是需要不断的设置它们。解决办法:全局uniform变量。

shader.vert

#version 330 core
layout (location = 0) in vec3 aPos;
layout (std140) uniform Matrices
{
    mat4 projection;
    mat4 view;
};
uniform mat4 model;
void main()
{
    // uniform 块中的变量可以直接访问,不需要加块名称作为前缀。
    gl_Position = projection * view * model * vec4(aPos, 1.0);
}

其中 layout (std140) 设置了Uniform块布局

使用std140布局计算出每个成员的对齐偏移量:

layout (std140) uniform ExampleBlock
{
                     // 基准对齐量       // 对齐偏移量
    float value;     // 4               // 0 
    vec3 vector;     // 16              // 16  (必须是16的倍数,所以 4->16)
    mat4 matrix;     // 16              // 32  (列 0)
                     // 16              // 48  (列 1)
                     // 16              // 64  (列 2)
                     // 16              // 80  (列 3)
    float values[3]; // 16              // 96  (values[0])
                     // 16              // 112 (values[1])
                     // 16              // 128 (values[2])
    bool boolean;    // 4               // 144
    int integer;     // 4               // 148
}; 
类型布局规则
标量,比如int和bool每个标量的基准对齐量为N。
向量2N或者4N。这意味着vec3的基准对齐量为4N。
标量或向量的数组每个元素的基准对齐量与vec4的相同。
矩阵储存为列向量的数组,每个向量的基准对齐量与vec4的相同。
结构体等于所有元素根据规则计算后的大小,但会填充到vec4大小的倍数。

我们已经讨论了如何在着色器中定义Uniform块,并设定它们的内存布局了,但我们还没有讨论该如何使用它们。

首先,我们需要调用glGenBuffers,创建一个Uniform缓冲对象。一旦我们有了一个缓冲对象,我们需要将它绑定到GL_UNIFORM_BUFFER目标,并调用glBufferData,分配足够的内存。

unsigned int uboExampleBlock;
glGenBuffers(1, &uboExampleBlock);
glBindBuffer(GL_UNIFORM_BUFFER, uboExampleBlock);
glBufferData(GL_UNIFORM_BUFFER, 152, NULL, GL_STATIC_DRAW); // 分配152字节的内存
glBindBuffer(GL_UNIFORM_BUFFER, 0);

UBO代码实现

具体实现请参照tag-UBO

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

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

相关文章

项目环境配置、不知晓问题自己搜索后得到的解答

目录 Anolis OS龙蜥操作系统 Kernel Selection 4.18.0(RHCK) Compatible with RHEL (kernel-4.18.0) 4.19.91(ANCK) Support Anolis OS verified platform (kernel-4.19.91) 这两个内核选择哪个比较好呢&#xff1f; 我的C盘有些满&#xff0c;我该如何删除一些我需要的东西…

docker网络访问和端口映射

docker网络访问和端口映射 文章目录 docker网络访问和端口映射1.docker容器网络1.1.创建一个centos7的容器1.2.docker网络原理图 2.端口映射2.1.创建一个新的IP2.2.多个IP端口映射2.3.随机端口命令 1.docker容器网络 指定映射&#xff08;docker 会 自动添加一条iptables规则来…

wisp5.0 学习日记2

学习日记 昨天的报错尝试1&#xff0c;在CCS中设置USB FET尝试2 csdn解决方案1尝试3 查看仿真器的驱动是否安装成功 昨天的报错 MSP430: Error initializing emulator: No USB FET was found 尝试1&#xff0c;在CCS中设置USB FET 打开CCS&#xff0c;选择“Window” -> …

在线文档编辑工具哪个更好?

在线文档编辑工具相当于一个轻量级、跨平台、多途径的Office。使用在线文档编辑工具&#xff0c;首先我们不用安装Office软件&#xff1b;其次在电脑网页上、手机小程序里我们都可以使用在线文档进行简单的编辑&#xff1b;最后我们编辑的文档可以实时更新、分享、协作等。今天…

供应商标准化管理难?云时通助力国药器械成功打造医疗器械行业SRM管理平台!

中国医疗器械有限公司(CMDC,简称“国药器械”)&#xff0c;始建于1966年&#xff0c;隶属于国药集团&#xff0c;是其医疗器械板块的主力军。国药器械有分子公司300家左右&#xff0c;年销售额300多亿&#xff0c;国内最大的医疗器械商业流通企业&#xff0c;产品覆盖医疗器械所…

软件测试简历?面试题?企业面试官想要什么?我不再和offer失之交臂...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 软件测试面试题简历…

vivado跨时钟域路径分析

若要查看跨时钟域路径分析报告&#xff0c;可选择以下内容之一来查看&#xff1a; A, Reports > Timing > Report Clock Interaction B, Flow Navigator > Synthesis > Report Clock Interaction C, Flow Navigator > Implementation > Report Clock Inte…

【网络安全】--win提权

win提权 提权目的提权常用命令提权实战常见的payload利用1. 安装虚拟机win2008和kali2. 创建普通用户3. 切换用户4. kali生成木马并发送到被攻击服务器上5. 被攻击方运行生成的木马文件7. 查看可利用漏洞8. 尝试利用exp提权 at/sc/ps命令提权at命令提权sc命令提权ps命令提权 提…

换个花样玩C++(8)吃不透内存布局,坑的是自己,万字经验告诉你类的内存布局

C++内存布局是老生常谈的话题,无论是笔试面试,都会涉及到该类问题,那么这一章节,我们就聊聊内存布局到底是怎么布局的,聊完之后我保证你仍然会回味无穷,并且我提供的几个例子也会让你再一步步踩入雷区。 C++程序的内存布局 C++的内存布局区域我们大体上分为四个:全局数据…

SubMain CodeIt.Right 2022.2 Crack

CodeIt.Right&#xff0c;从源头上提高产品质量&#xff0c;在编写代码时获取有关问题的实时反馈&#xff0c;支持最佳实践和合规性&#xff0c;自动执行代码审查&#xff0c;轻松避免与您的群组无关的通知&#xff0c;一目了然地了解代码库的运行状况 自动执行代码审查 使用自…

ICMP协议和NAT技术

文章目录 ICMP协议ICMP功能NAT技术NAT技术背景 ICMP协议 ICMP协议是一个网络层协议 一个新搭建好的网络, 往往需要先进行一个简单的测试, 来验证网络是否畅通; 但是IP协议并不提供可靠传输. 如果丢包了, IP协议并不能通知传输层是否丢包以及丢包的原因 ICMP功能 ICMP正是提…

K8s常见面试题19问

K8s常见面试题19问 收集了一些K8s常见问题和同学们面试常被问到的问题. 如果有新的面试题私聊或者留言给我 1. Docker和虚拟机有那些不同 虚拟化环境下每个 VM 是一台完整的计算机&#xff0c;在虚拟化硬件之上运行所有组件&#xff0c;包括其自己的操作系统。 容器之间可以共…

什么叫用空间换时间,用时间换空间

什么叫做用空间换时间 用空间换时间是指为了提高程序或算法的效率&#xff0c;将计算机程序中的时间复杂度转化为空间复杂度&#xff0c;即通过使用更多的空间来减少程序运行所需的时间。这种技术在某些情况下可以大幅缩短程序的执行时间&#xff0c;但也会导致程序需要更大的…

【软件开发】大规模分布式系统的容错架构设计

大规模分布式系统的容错架构设计 假设有一个数据库&#xff0c;数据库里有一张特别大的表&#xff0c;里面有几十亿&#xff0c;甚至上百亿的数据。更进一步说&#xff0c;假设这一张表的数据量多达几十个 TB&#xff0c;甚至上百个 TB&#xff0c;那么如果用 MySQL 之类的数据…

功率信号源的作用是什么意思

功率信号源是指集信号发生器与功率放大器为一体的电子测量仪器&#xff0c;它具有高电压、大功率的特点&#xff0c;在电子实验室中能够帮助用来驱动压电陶瓷、换能器以及电磁线圈等&#xff0c;可以有效的帮助电子工程师解决驱动负载和放大功率的问题。同时&#xff0c;功率信…

使用python实现背单词功能,单词本存放在txt文件中,最后统计出回答的正确题数和错误题数。

一、编程题目 编程题目&#xff1a;使用python实现背单词功能&#xff0c;单词本存放在txt文件中&#xff0c;最后统计出回答的正确题数和错误题数。 单词本的内容如下&#xff1a; danciben.txt内容如下&#xff08;按照格式&#xff0c;可自行定义单词本的内容&#xff09;&a…

创建 Node REST API 文档

为自己开发的 Node REST API 生成文档&#xff0c;基本有两种方法&#xff1a; 1 极简版 此方法就是自己写一个文件&#xff0c;记录 API&#xff0c;不需要安装额外的 package&#xff0c;然后 app.js 增加一个 route 然后从浏览器查看这个文件就可以。 步骤如下&#xff1a…

酷家乐x极盾科技:“智能安全决策平台”助力日均十亿级日志分析

企业网络环境中每天都会产生大量的网络日志&#xff0c;还有工作站&#xff0c;服务器&#xff0c;路由器和防火墙等网络设备中的日志对网络安全的提升具有重要意义。充分利用好它们可以帮助企业及时发现潜在的风险和安全漏洞&#xff0c;把网络环境中存在的威胁扼杀在摇篮中。…

10年IT老兵亲述SpringCloud开发从入门到实战文档

前言 首先给大家看一张图&#xff0c;不知道图上这些springcloud的技术知识点&#xff0c;大家是否都精通而灵活运用了呢&#xff1f; 如果没有精通灵活运用的话&#xff0c;小编将用此文来带大家一步步来深入学习这些技术知识&#xff0c;接下来将从Spring Boot微框架搭建、S…

Makefile及cmake学习

Makefile及cmake学习 1. g&#xff0c;gcc以及cpp的区别2. Makefile2.1 介绍一个例子2.2 避免头文件重复包含的方法2.2.1 宏定义2.2.2 #pargma once 2.3 使用Makefile编译文件2.3.1 手动编译2.3.2 Makefile编译-版本12.3.3 Makefile编译-版本22.3.4 Makefile编译-版本32.3.5 Ma…