本篇在讲什么 本篇为蓝宝书学习笔记 原子计数器 本篇适合什么 适合初学OpenGL的小白 本篇需要什么 对 C++语法有简单认知 对 OpenGL有简单认知 最好是有 OpenGL超级宝典蓝宝书 依赖 Visual Studio编辑器 本篇的特色 具有全流程的图文教学 重实践,轻理论,快速上手 提供全流程的源码内容 |
![]() ★提高阅读体验★ 👉 ♠ 一级标题 👈👉 ♥ 二级标题 👈👉 ♣ 三级标题 👈👉 ♦ 四级标题 👈 |
♠ 原子计数器
- 什么是原子计数器
原子计数器是一种特殊的变量,表示的是多个着色器之间共享的存储,这个存储和一个缓冲对象关联,而且我们可以调用特定的函数进行原子内存操作
- 原子计数器的作用
变量本身的功能是用于计数
♠ 用法
♥ 声明
layout (binding=3,offset=8) uniform atomic_uint my_variable;
声明了原子计数器my_variable,并绑定在3上,其中起始位置是8
♥ 绑定
GLuint buf;
glGenBuffers(1, &buf);
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buf);
glBufferData(GL_ATOMIC_COUNTER_BUFFER, 16 * sizeof(GLuint), NULL, GL_DYNAMIC_COPY);
glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 3, buf);
同uniform
和buffer
相同,可以使用相同的方式将缓存对象绑定至绑定点上,特定参数GL_ATOMIC_COUNTER_BUFFER
♥ 重置
在使用前我们要重置计数器变量,书中提供了三种方式重设变量
- glBufferSubData
const GLuint zero = 0;
glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 2 * sizeof(GLuint), sizeof(GLuint), &zero);
通过glBufferSubData
更新指定位置的数据
- glMapBufferRange
GLuint * data = (GLuint *)glMapBufferRange(GL ATOMIC COUNTER BUFFER, 0, 16 * sizeof(GLuint), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT);
data[2] = 0;
glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
通过glMapBufferRange
获取变量地址后直接赋值
- glClearBufferSubData
glClearBufferSubData(GL_ATOMIC_COUNTER_BUFFER, GL_R32UI, 2 * sizeof(GLuint), sizeof(GLuint), GL_RED_INTEGER, GL_UNSIGNED_INT, &zero);
通过glClearBufferSubData
赋值
♥ 计数
OpenGL提供了三种用于计数的着色器函数
- 加一
uint atomicCounterIncrement(atomic_uint a);
- 减一
uint atomicCounterDecrement(atomic_uint a);
- 获取值
uint atomicCounter(atomic_uint a);
♠ 案例
我们来看一个完整的演示示例吧,改例子将一个计数器绑定到缓存后并清零,通过计数器的数量来判断颜色的显示
注:该例子直接修改OpenGl超级宝典官方示例singletri.cpp
,只需修改startup
方法即可
virtual void startup()
{
static const char * vs_source[] =
{
"#version 450 core \n"
" \n"
" \n"
"void main(void) \n"
"{ \n"
" const vec4 vertices[] = vec4[](vec4( 0.25, -0.25, 0.5, 1.0), \n"
" vec4(-0.25, -0.25, 0.5, 1.0), \n"
" vec4( 0.25, 0.25, 0.5, 1.0)); \n"
" \n"
" gl_Position = vertices[gl_VertexID]; \n"
"} \n"
};
static const char * fs_source[] =
{
"#version 450 core \n"
" \n"
" \n"
"layout (binding=0) uniform atomic_uint my_variable; \n"
" \n"
"out vec4 color; \n"
" \n"
"void main(void) \n"
"{ \n"
" uint counter = atomicCounterIncrement(my_variable); \n"
" if(counter>20000){ \n"
" color = vec4(1.0, 0.8, 1.0, 1.0); \n"
" }else{ \n"
" color = vec4(0.0, 0.8, 1.0, 1.0); \n"
" } \n"
"} \n"
};
program = glCreateProgram();
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, fs_source, NULL);
glCompileShader(fs);
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, vs_source, NULL);
glCompileShader(vs);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// 绑定缓存
GLuint buf;
glGenBuffers(1, &buf);
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buf);
glBufferData(GL_ATOMIC_COUNTER_BUFFER, 16 * sizeof(GLuint), NULL, GL_DYNAMIC_COPY);
glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, buf);
// 清零计数器
const GLuint zero = 0;
glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 2 * sizeof(GLuint), sizeof(GLuint), &zero);
}
在counter>20000
下显示效果如下
在counter<20000
下显示效果如下
♠ 推送
- Github
https://github.com/KingSun5
♠ 结语
若是觉得博主的文章写的不错,不妨关注一下博主,点赞一下博文,另博主能力有限,若文中有出现什么错误的地方,欢迎各位评论指摘。