深圳设计网站速成班,网站音频播放器代码,聊天软件开发哪个好点,wordpress主题仪表盘一、OpenGL的UBO 在OpenGL Shader中#xff0c;如果逻辑比较复杂#xff0c;使用的uniform变量较多。通常多个着色器使用同一个uniform变量。由于uniform变量的位置是着色器链接时候产生的#xff0c;因此它在应用程序中获得的索引会有变化。Uniform Buffer Object#xff…一、OpenGL的UBO 在OpenGL Shader中如果逻辑比较复杂使用的uniform变量较多。通常多个着色器使用同一个uniform变量。由于uniform变量的位置是着色器链接时候产生的因此它在应用程序中获得的索引会有变化。Uniform Buffer ObjectUBO是一种优化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*/templatetypename Tvoid 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)*/templatetypename Tvoid SetSubData(const T p_data, std::reference_wrappersize_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_castGLint(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函数指定其偏移值与数据大小即可。 templatetypename Tinline 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();}templatetypename Tinline void UniformBuffer::SetSubData(const T p_data, std::reference_wrappersize_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 ObjectSSBO着色器存储缓存对象其行为类似于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大同小异。