【Overload游戏引擎分析】UBO与SSBO的封装

一、OpenGL的UBO

  在OpenGL Shader中,如果逻辑比较复杂,使用的uniform变量较多。通常多个着色器使用同一个uniform变量。由于uniform变量的位置是着色器链接时候产生的,因此它在应用程序中获得的索引会有变化。Uniform Buffer Object(UBO)是一种优化uniform变量访问,不同着色器直接共享unfiorm数据的方法。  

在Overload引擎中,很多Shader包含如下片段,这里就是定义了一个UBO变量。 它将MVP矩阵一起放入到UBO变量中。

layout (std140) uniform EngineUBO
{mat4    ubo_Model;mat4    ubo_View;mat4    ubo_Projection;vec3    ubo_ViewPos;float   ubo_Time;
};

std140是内存布局限定符,除此之外还有std430、binding、packed等限定符。

二·、Overload对UBO的封装

   Overload引擎中对UBO的封装在UniformBuffer.h、UniformBuffer.inl、UniformBuffer.cpp文件中,将其操作包装成了一个类UniformBuffer。使用的时候先调用Bind,结束后UnBind,设置值使用SetSubData。

namespace OvRendering::Buffers
{/*** OpenGL UBO的封装*/class UniformBuffer{public:/*** Create a UniformBuffer* @param p_size (Specify the size in bytes of the UBO data)* @param p_bindingPoint (Specify the binding point on which the uniform buffer should be binded)* @parma p_offset (The offset of the UBO, sizeof previouses UBO if the binding point is != 0)* @param p_accessSpecifier*/UniformBuffer(size_t p_size, uint32_t p_bindingPoint = 0, uint32_t p_offset = 0, EAccessSpecifier p_accessSpecifier = EAccessSpecifier::DYNAMIC_DRAW);/*** Destructor of the UniformBuffer*/~UniformBuffer();/*** Bind the UBO*/void Bind();/*** Unbind the UBO*/void Unbind();/*** Set the data in the UBO located at p_offset to p_data* @param p_data* @param p_offset*/template<typename T>void SetSubData(const T& p_data, size_t p_offset);/*** Set the data in the UBO located at p_offset to p_data* @param p_data* @param p_offsetInOut (Will keep track of the current stride of the data layout)*/template<typename T>void SetSubData(const T& p_data, std::reference_wrapper<size_t> p_offsetInOut);/*** Return the ID of the UBO*/uint32_t GetID() const;/*** Bind a block identified by the given ID to given shader* @param p_shader* @param p_uniformBlockLocation* @param p_bindingPoint*/static void BindBlockToShader(OvRendering::Resources::Shader& p_shader, uint32_t p_uniformBlockLocation, uint32_t p_bindingPoint = 0);/*** Bind a block identified by the given name to the given shader* @param p_shader* @param p_name* @param p_bindingPoint*/static void BindBlockToShader(OvRendering::Resources::Shader& p_shader, const std::string& p_name, uint32_t p_bindingPoint = 0);/*** Return the location of the block (ID)* @param p_shader* @param p_name*/static uint32_t GetBlockLocation(OvRendering::Resources::Shader& p_shader, const std::string& p_name);private:uint32_t m_bufferID;};
}#include "OvRendering/Buffers/UniformBuffer.inl"

其具体实现在UniformBuffer.cpp中。我们先看看构造函数代码:

OvRendering::Buffers::UniformBuffer::UniformBuffer(size_t p_size, uint32_t p_bindingPoint, uint32_t p_offset, EAccessSpecifier p_accessSpecifier)
{// 生成bufferglGenBuffers(1, &m_bufferID);// 绑定UBOglBindBuffer(GL_UNIFORM_BUFFER, m_bufferID);// 分配内存glBufferData(GL_UNIFORM_BUFFER, p_size, NULL, static_cast<GLint>(p_accessSpecifier));glBindBuffer(GL_UNIFORM_BUFFER, 0);// 将缓存对象m_bufferID绑定到索引为p_bindingPoint的UBO上glBindBufferRange(GL_UNIFORM_BUFFER, p_bindingPoint, m_bufferID, p_offset, p_size);
}

在构造函数中直接创建了UBO的buffer,并绑定到索引是p_bindingPoint的UBO上。这里用到了OpenGL函数glBindBufferRange,如无需指定偏移量与size值可使用glBindBufferBase函数。

UniformBuffer.cpp中Bind()、UnBind()过于简单不再分析。往下接着看有个static函数BindBlockToShader。这个函数主要是显式绑定一个uniform块到p_bindingPoint索引,这样可以绑定同一个缓存。这里使用到了glUniformBlockBinding函数,这个函数主要是显示指定BUO的索引,可以保证多个不同的Shader程序之间UBO的索引是一样的,但需要在调用glLinkProgram之前调用。

void OvRendering::Buffers::UniformBuffer::BindBlockToShader(OvRendering::Resources::Shader& p_shader, uint32_t p_uniformBlockLocation, uint32_t p_bindingPoint)
{glUniformBlockBinding(p_shader.id, p_uniformBlockLocation, p_bindingPoint);
}void OvRendering::Buffers::UniformBuffer::BindBlockToShader(OvRendering::Resources::Shader& p_shader, const std::string& p_name, uint32_t p_bindingPoint)
{glUniformBlockBinding(p_shader.id, GetBlockLocation(p_shader, p_name), p_bindingPoint);
}// 获取UBO的索引位置
uint32_t OvRendering::Buffers::UniformBuffer::GetBlockLocation(OvRendering::Resources::Shader& p_shader, const std::string& p_name)
{return glGetUniformBlockIndex(p_shader.id, p_name.c_str());
}

但在Overload引擎中,调用这个方法是在调用glProgram之后调用的,而且索引值使用的是GetBlockLocation获取的,这也是UBO在Shader的默认索引值,所以这个方法应该是可以删除的。我注释这个方法使用上没有发现什么问题。

最后看一下如何给UBO设置值,其实现是在UniformBuffer.inl文件中,主要使用glBufferSubData函数,指定其偏移值与数据大小即可。

	template<typename T>inline void UniformBuffer::SetSubData(const T& p_data, size_t p_offsetInOut){Bind();glBufferSubData(GL_UNIFORM_BUFFER, p_offsetInOut, sizeof(T), std::addressof(p_data));Unbind();}template<typename T>inline void UniformBuffer::SetSubData(const T& p_data, std::reference_wrapper<size_t> p_offsetInOut){Bind();size_t dataSize = sizeof(T);glBufferSubData(GL_UNIFORM_BUFFER, p_offsetInOut.get(), dataSize, std::addressof(p_data));p_offsetInOut.get() += dataSize;Unbind();}

三、OpenGL的SSBO

Shader Storage Buffer Object(SSBO),着色器存储缓存对象,其行为类似于UBO,但其功能上更为强大。首先,着色器可以写入buffer块,修改其内容并呈现给其他Shader或应用程序本身。其次,可以在渲染之前再觉得其大小,而不是编译与链接时。在Overload中,灯光信息是用SSBO存储的,看以下Shader片段:

layout(std430, binding = 0) buffer LightSSBO
{mat4 ssbo_Lights[];
};

在着色器中可以使用length()获取ssbo_Lights的长度。

设置SSBO的方式与设置UBO类似,不过glBindBuffer()、glBindBufferRange()、glBindBufferBase()需要使用GL_SHADER_STORAGE_BUFFER作为目标参数。

四、Overload对SSBO的封装

Overload是将SSBO的操作封装到类ShaderStorageBuffer中,具体代码就不分析了,与UBO大同小异。

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

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

相关文章

如何写好一个接口

接口设计 接口要注意拓展性&#xff0c;设计得灵活一些&#xff0c;应对业务的变化。字段尽量不要耦合在一起。接口尽量通用。能调用一次完成的&#xff0c;不用调用两次。网络IO是很慢的。接口的字段&#xff0c;尽量少一些&#xff0c;字段越多&#xff0c;越混乱&#xff0…

国家开放大学 模拟试题训练

2208 政治学原理 参考试题 一、选择题&#xff08;每题2分&#xff0c;共20分&#xff0c;每题至少有一个答案&#xff0c;多选少选均不能得分&#xff09; 1.柏拉图在《理想国》-书中明确指出&#xff0c;政治的本质在于公正&#xff0c;一个“理想国”具有( )美德。 A.智慧…

【SV中的多线程fork...join/join_any/join_none】

SV中fork_join/fork_join_any/fork_join_none 1 一目了然1.1 fork...join1.2 fork...join_any1.3 fork...join_none 2 总结 SV中fork_join和fork_join_any和fork_join_none; Note: fork_join在Verilog中也有&#xff0c;只有其他的两个是SV中独有的&#xff1b; 1 一目了然 1.…

操作系统 OS

本文章是学习《操作系统》慕课版 和 王道《2024年 操作系统 考研复习指导》后所做的笔记&#xff0c;其中一些图片来源于学习资料。 目录 概念&#xff08;定义&#xff09; 目标 方便性 有效性 可扩充性 开放性 作用 OS 作为用户与计算机硬件系统之间的接口 — 人机交…

Stream流最佳实战

Stream流最佳实战 stream 进行排序、分组、多级分组、交集、并集、差集等 package com.al.admin.utils;import cn.hutool.core.util.ObjectUtil; import lombok.Data; import org.springframework.util.StringUtils;import java.text.SimpleDateFormat; import java.util.*; …

1、【gradio】快速开始,构建自己的机器学习的应用

1、【gradio】快速开始,构建自己的机器学习的应用 Gradio能做什么Hello, WorldInterface类组件属性多个输入和输出组件一个图片的ExampleChatbot(聊天机器人)Blocks:更多的灵活性和控制Hello, Blocks更复杂一点的实现先决条件:Gradio 需要 Python 3.8 或更高版本。 Gradio…

仅用61行代码,你也能从零训练大模型

本文并非基于微调训练模型&#xff0c;而是从头开始训练出一个全新的大语言模型的硬核教程。看完本篇&#xff0c;你将了解训练出一个大模型的环境准备、数据准备&#xff0c;生成分词&#xff0c;模型训练、测试模型等环节分别需要做什么。AI 小白友好~文中代码可以直接实操运…

取出SQLite数据(基本游标)

前面一节中已经为Starbuzz创建了一个SQLite帮助器。 目前还是从Java Drink类获取数据&#xff0c;这时候要修改这个应用从SQLite数据库获取数据。 本文所有代码均存放于 https://github.com/MADMAX110/Starbuzz 一、修改DrinkActivity来使用Starbuzz数据库 基本步骤&#xff…

Puppeteer基础知识(一)

Puppeteer基础知识&#xff08;一&#xff09; Puppeteer基础知识&#xff08;一&#xff09;一、简介二、其他一些自动化测试工具三、安装与使用四、Puppeteer常用命令五、常见问题解决&#xff1a; 一、简介 Puppeteer 是一个强大而灵活的工具&#xff0c;可以用于网页爬虫、…

Transformer预测 | Pytorch实现基于Transformer 的锂电池寿命预测(CALCE数据集)

文章目录 效果一览文章概述模型描述程序设计参考资料效果一览 文章概述 Pytorch实现基于Transformer 的锂电池寿命预测,环境为pytorch 1.8.0,pandas 0.24.2 随着充放电次数的增加,锂电池的性能逐渐下降。电池的性能可以用容量来表示,故寿命预测 (RUL) 可以定义如下: SOH(t…

QT位置相关函数

Qt&#xff08;Qt Framework&#xff09;是一个流行的C应用程序开发框架&#xff0c;提供了丰富的位置相关函数和类&#xff0c;用于处理窗口、窗口小部件和图形的位置和几何操作。以下是一些常用的Qt位置相关函数和类&#xff1a; QPoint&#xff1a;QPoint类表示一个二维点的…

RTC 时间、闹钟

实时时钟RTC是一个独立的定时器。RTC模块拥有一个连续计数的计数器&#xff0c;在软件配置下&#xff0c;可以提供时钟日历的功能。修改计数器的值可以重新设置当前时间和日期 RTC还包含用于管理低功耗模式的自动唤醒单元。 在掉电情况下 RTC仍可以独立运行 只要芯片的备用电源…

vue3中使用插件vite-plugin-svg-icons

在vue3 vite 项目中使用svg图标 插件&#xff1a;vite-plugin-svg-icons 预加载 在项目运行时就生成所有图标,只需操作一次 dom高性能 内置缓存,仅当文件被修改时才会重新生成 安装 yarn add vite-plugin-svg-icons -D # or npm i vite-plugin-svg-icons -D # or pnpm inst…

总结html5中常见的选择器

HTML5并没有引入新的选择器类型&#xff0c;它仍然使用CSS选择器来选择和操作HTML元素。HTML5中仍然可以使用CSS2和CSS3中定义的各种选择器。以下是HTML5中常见的选择器类型&#xff1a; 1. 元素选择器&#xff08;Element Selector&#xff09;&#xff1a;使用元素名称作为选…

实现协议互通:探索钡铼BL124EC的EtherCAT转Ethernet/IP功能

钡铼BL124EC是一种用于工业网络通信的网关设备&#xff0c;专门用于将EtherCAT协议转换成Ethernet/IP协议。它充当一个桥梁&#xff0c;连接了使用不同协议的设备&#xff0c;使它们能够无缝地进行通信和互操作。 具体来说&#xff0c;BL124EC通过支持EtherCAT&#xff08;以太…

2023,全网最真实的自动化测试学习路线,看不懂来打我!

随着测试行业的发展&#xff0c;“会代码”越来越成为测试工程师的一个标签。打开各大招聘网站&#xff0c;测试工程师月薪一万以上基本都有一个必备技能&#xff0c;那就是自动化测试。那么自动化测试到底难不难呢&#xff1f;下面我将会将我的经历讲给大家听&#xff0c;希望…

安卓App使用HttpURLConnection发送请求与上传文件

安卓原生App开发时常用的http开发工具 系统内置http请求工具为 HttpURLConnectionhttpClient 是 apache 的开源工具okHttp 使用更简单&#xff0c;语法相对HttpURLConnection也简洁了许多&#xff0c;需要在graddle添加依赖。 本文主要讲解如何使用HttpURConnection向服务器发…

【java基础学习】之DOS命令

#java基础学习 1.常用的DOS命令&#xff1a; dir:列出当前目录下的文件以及文件夹 md: 创建目录 rd:删除目录cd:进入指定目录 cd.. :退回到上级目录 cd\ : 退回到根目录 del:删除文件 exit:退出dos命令行 1.dir:列出当前目录下的文件以及文件夹 2.md: 创建目录 …

[NewStarCTF 2023 公开赛道] week1 Crypto

brainfuck 题目描述&#xff1a; [>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<-]>>>>>>>.>----.<-----.>-----.>-----.<<<-.>>..…

黑豹程序员-架构师学习路线图-百科:AJAX

文章目录 1、什么是AJAX2、发展历史3、工作原理4、一句话概括 1、什么是AJAX Ajax即Asynchronous&#xff08;呃森可乐思&#xff09; Javascript And XML&#xff08;异步JavaScript和XML&#xff09; 在 2005年被Jesse James Garrett&#xff08;杰西詹姆斯加勒特&#xff09…