OpenGL缓冲区对象之Atomic Counter Object



简介


Atomic Counter是OpenGL 4.2版本通过GL_ARB_shader_atomic_counters扩展引入的新特性,它可以在各种着色语言中使用。Atomic Counter具体来说指的是在缓冲区对象(Buffer Object)中存储着一个或者多个可以用来计数的变量值,对这些变量定义了特定的操作方式,可以让它们在着色语言中进行加一和减一的操作,除此之后其他所有的操作都是非法的。

关于Atomic Counter的使用场景,一个简单的案例是统计场景中哪些像素会先进行渲染。具体的实现思路:当我们调用片元Shader对像素进行着色的时候,我们可以让atomic Counter变量值加1,然后将这个值转换成一种颜色来渲染我们的像素,这样我们就可以很清楚看到那些像素点是先渲染的,哪些像素点是后渲染的了。

使用


首先我们需要创建Atomic Counter的缓冲区,和其他类型的缓冲区的实现过程都是一样的。

GLuint atomicsBuffer;
glGenBuffers(1, &atomicsBuffer);
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicsBuffer);
glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint) * 3, NULL, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);

上面的代码生成了一个Atomic Counter Object对象,并且在它的存储区中存放了三个Atomic Counter类型的变量(Atomic Counter本质上是一个GLuint类型的变量,占4个字节) 与其他缓冲区一样,更新和获取Atomic Counter缓冲区对象的方法如下所示:

  • 更新

  1. GLuint *userCounters;  
  2. glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicsBuffer);  
  3. userCounters = (GLuint*)glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER,  
  4.                                          0 ,  
  5.                                          sizeof(GLuint) * 3,  
  6.                                          GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT);  
  7. memset(userCounters, 0, sizeof(GLuint) *3 );  
  8. // unmap the buffer  
  9. glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);  
  10.   
  11. 或者使用glBufferSubData的方式进行更新  
  12.   
  13. glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_AtomicCountersBuffer);  
  14. GLuint a[3] = {0,0,0};  
  15. glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0 , sizeof(GLuint) * 3, a);  
  16. glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);  
GLuint *userCounters;
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicsBuffer);
userCounters = (GLuint*)glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER,
                                         0 ,
                                         sizeof(GLuint) * 3,
                                         GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
memset(userCounters, 0, sizeof(GLuint) *3 );
// unmap the buffer
glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);

或者使用glBufferSubData的方式进行更新

glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_AtomicCountersBuffer);
GLuint a[3] = {0,0,0};
glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0 , sizeof(GLuint) * 3, a);
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);


  • 获取

  1. GLuint *userCounters;  
  2. glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicsBuffer);  
  3. userCounters = (GLuint*)glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER,  
  4.                                          0,  
  5.                                          sizeof(GLuint) * 3,  
  6.                                          GL_MAP_READ_BIT  
  7.                                         );  
  8. redPixels = userCounters[0];  
  9. greenPixels = userCounters[1];  
  10. bluePixels = userCounters[2];  
  11. glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);  
  12.   
  13. 或者使用另一种方式来获取  
  14.   
  15. GLuint userCounters[3];  
  16. glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_AtomicCountersBuffer);  
  17. glGetBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint) * 3, userCounters);  
  18. glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);  
  19. redPixels = userCounters[0];  
  20. greenPixels = userCounters[1];  
  21. bluePixels = userCounters[2];  
GLuint *userCounters;
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicsBuffer);
userCounters = (GLuint*)glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER,
                                         0,
                                         sizeof(GLuint) * 3,
                                         GL_MAP_READ_BIT
                                        );
redPixels = userCounters[0];
greenPixels = userCounters[1];
bluePixels = userCounters[2];
glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);

或者使用另一种方式来获取

GLuint userCounters[3];
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_AtomicCountersBuffer);
glGetBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint) * 3, userCounters);
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
redPixels = userCounters[0];
greenPixels = userCounters[1];
bluePixels = userCounters[2];


Shader中的设置


当我们在shader中需要使用Atomic Counter的时候,我们可以定义Atomic Counter类型的变量atomic_uint,在我们定义atomic_uint类型变量的时候我们需要设置这些变量对应到AtomicCounter缓冲区对象存储空间的位置和偏移量,一般来说定义Atomic Counter变量的方式如下:

layout (binding = 1, offset = 0) uniform atomic_uint atRed;
layout (binding = 2, offset = 0) uniform atomic_uint atGreen;
layout (binding = 2, offset = 4) uniform atomic_uint atBlue;

atRed变量对应的binding point是1,偏移量是0 atGreen对应的binding point是2,偏移量是0 atBlue对应的binding point是2,偏移量是4(正好越过atGreen的4个字节) 需要注意的是当我们设置两个变量同样的binding和offset,那么他们实际上是同一个atomic_uint

layout (binding = 1, offset = 0) uniform atomic_uint at1;
layout (binding = 1, offset = 0) uniform atomic_uint at2;

at1和at2指向的是同一个变量

尽管atomic_uint类型的变量作为uniform来使用,但是它和samplers一样并不能用在Uniform Block之中

示例


atomic_int支持的操作非常有限,仅包含一下几种:

 
 
  1. //获取  
  2. uint atomicCounter(atomic_uint c);  
  3.   
  4. // 减一并返回新值  
  5. uint atomicCounterDecrement(atomic_uint c);   
  6.   
  7. //加一并返回旧值  
  8. uint atomicCounterIncrement(atomic_uint c);  
//获取
uint atomicCounter(atomic_uint c);

// 减一并返回新值
uint atomicCounterDecrement(atomic_uint c); 

//加一并返回旧值
uint atomicCounterIncrement(atomic_uint c);

下面这个例子来自OSG Examples,我将它转换成OpenGL的方式实现: 实现的内容:记录一帧绘制中的像素绘制顺序,先绘制的颜色呈现淡黄色,后绘制的颜色黄色逐渐加深直至为(1,1,0)的黄色,实现代码如下:

 
 
  1. #pragma comment(lib, "glew32.lib")  
  2. #pragma comment(lib, "freeglut.lib")  
  3.   
  4. #include <gl/glew.h>  
  5. #include <gl/freeglut.h>  
  6. #include <iostream>  
  7. #include <vector>  
  8. #include <algorithm>  
  9.   
  10. #include "glshadertools.h"  
  11.   
  12. GLuint          programID;  
  13. GLuint          vboID;  
  14. GLuint     eboID;  
  15.   
  16. GLuint atomicCounterArrayRedAndGreen[2];  
  17. GLuint atomicCounterArrayBlue[1];  
  18. GLuint acboRedAndGreen;  
  19. GLuint acboBlue;  
  20. GLfloat invNumPixel;  
  21. //  
  22.   
  23. GLfloat vertices[] = {  
  24.         -1.0f, 1.0f,0.0f,  
  25.         -1.0f, -1.0f,0.0f,  
  26.         1.0f, -1.0f,0.0f,  
  27.         1.0f, 1.0f, 0.0f  
  28. };  
  29.   
  30. GLuint indices[] = {  
  31.         0,1,2,  
  32.         2,3,0  
  33. };  
  34.   
  35. //  
  36. GLfloat xRot;             
  37. GLfloat yRot;  
  38. GLfloat zoom = -10.0f;  
  39.   
  40. bool mouseLeftDown;  
  41. float mouseX, mouseY;  
  42.   
  43.   
  44.   
  45. void    init()  
  46. {  
  47.         programID = gltLoadShaderProgram("atomiccounter.vert""atomiccounter.frag");  
  48.           
  49.         glGenBuffers(1, &vboID);  
  50.         glBindBuffer(GL_ARRAY_BUFFER, vboID);  
  51.         glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);  
  52.         glBindBuffer(GL_ARRAY_BUFFER, 0);  
  53.   
  54.         glGenBuffers(1, &eboID);  
  55.         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboID);  
  56.         glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);  
  57.         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);  
  58.   
  59.         atomicCounterArrayBlue[0] = 0;  
  60.         atomicCounterArrayRedAndGreen[0] = 0;  
  61.         atomicCounterArrayRedAndGreen[1] = 0;  
  62.   
  63.         glGenBuffers(1, &acboRedAndGreen);  
  64.         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, acboRedAndGreen);  
  65.         glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint)*2, NULL, GL_STREAM_COPY);  
  66.         glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint)*2, atomicCounterArrayRedAndGreen);  
  67.         glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, acboRedAndGreen);  
  68.           
  69.         glGenBuffers(1, &acboBlue);  
  70.         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, acboBlue);  
  71.         glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_STREAM_COPY);  
  72.         glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 2, acboBlue);  
  73.   
  74.         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);  
  75.   
  76.         GLint invNumPixelLocation;   
  77.         invNumPixelLocation = glGetUniformLocation(programID, "invNumPixel");  
  78.         glProgramUniform1f(programID, invNumPixelLocation, 1.0f/(800.0f*600.0f));  
  79.   
  80.         glUseProgram(programID);  
  81. }  
  82.   
  83.   
  84. void reshape(int w, int h)  
  85. {  
  86.         glViewport(0, 0, (GLsizei)w, (GLsizei)h);  
  87.         glMatrixMode(GL_PROJECTION);  
  88.         glLoadIdentity();  
  89.         gluPerspective(60.0f, (float)(w)/h, 0.1f, 1000.0f);  
  90.         glMatrixMode(GL_MODELVIEW);  
  91.         glLoadIdentity();  
  92. }  
  93.   
  94.   
  95. void    display()  
  96. {  
  97.         glClearColor(0, 0, 0, 0);  
  98.         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  
  99.         glColor3f(1.0f, 0.0f, 1.0f);  
  100.   
  101.         glLoadIdentity();  
  102.   
  103.         glTranslatef(0, 0, zoom);  
  104.         glRotatef(xRot, 1, 0, 0);   // pitch  
  105.         glRotatef(yRot, 0, 1, 0);   // heading  
  106.   
  107.         //更新蓝色成分缓冲区中的数据为0,让绘制结果呈现黄色  
  108.         GLuint *userCounters;  
  109.         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, acboBlue);  
  110.         userCounters = (GLuint*)glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER,  
  111.                 0,  
  112.                 sizeof(GLuint) * 1,  
  113.                 GL_MAP_WRITE_BIT  
  114.                 );  
  115.         atomicCounterArrayBlue[0] = 0;  
  116.         glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);  
  117.   
  118.         //将蓝色成分缓冲区中的数据设置为0  
  119.         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, acboBlue);  
  120.         glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), &atomicCounterArrayBlue);  
  121.         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);  
  122.   
  123.         glEnableClientState(GL_VERTEX_ARRAY);  
  124.         glEnableClientState(GL_INDEX_ARRAY);  
  125.         glBindBuffer(GL_ARRAY_BUFFER, vboID);  
  126.         glVertexPointer(3, GL_FLOAT, 0, 0);  
  127.         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboID);  
  128.         glIndexPointer(GL_UNSIGNED_INT, 0, 0);  
  129.           
  130.         glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);  
  131.   
  132.         glBindBuffer(GL_ARRAY_BUFFER, 0);  
  133.         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);  
  134.         glDisableClientState(GL_VERTEX_ARRAY);  
  135.         glDisableClientState(GL_INDEX_ARRAY);  
  136.   
  137.         glutSwapBuffers();  
  138.   
  139. //  
  140.         //一帧结束之后的操作  
  141.           
  142.         //获取前一帧绘制的像素总数(记录在蓝色成分的AtomicBuffer之中)  
  143.         //并将这个值设置给invNumPixel  
  144.         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, acboBlue);  
  145.         GLubyte *src = (GLubyte*)glMapBuffer(GL_ATOMIC_COUNTER_BUFFER, GL_READ_ONLY);  
  146.         if (src)  
  147.         {  
  148.                 memcpy((void*)atomicCounterArrayBlue, src, 4);  
  149.         }  
  150.         glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);  
  151.   
  152.         unsigned int numPixel = std::max(1u, atomicCounterArrayBlue[0]);  
  153.   
  154.         GLint invNumPixelLocation;   
  155.         invNumPixelLocation = glGetUniformLocation(programID, "invNumPixel");  
  156.         GLfloat invNumPixelValue;  
  157.         glGetUniformfv(programID, invNumPixelLocation, &invNumPixelValue);  
  158.         glProgramUniform1f(programID, invNumPixelLocation, 1.0f / static_cast<float>(numPixel));  
  159.   
  160.         //将表示红绿成分的AtomicBuffer设置为0  
  161.         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, acboRedAndGreen);  
  162.         userCounters = (GLuint*)glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER,  
  163.                 0,  
  164.                 sizeof(GLuint) * 2,  
  165.                 GL_MAP_READ_BIT  
  166.                 );  
  167.         atomicCounterArrayRedAndGreen[0] = 0;  
  168.         atomicCounterArrayRedAndGreen[1] = 0;  
  169.         glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);  
  170. }  
  171.   
  172.   
  173.   
  174. void mouse(int button, int state, int x, int y)  
  175. {  
  176.         mouseX = (float)x;  
  177.         mouseY = (float)y;  
  178.   
  179.         switch (button)  
  180.         {  
  181.         case GLUT_LEFT_BUTTON:  
  182.                 {  
  183.                         if (state == GLUT_DOWN) {  
  184.                                 mouseLeftDown = true;  
  185.                         } else if (state == GLUT_UP) {  
  186.                                 mouseLeftDown = false;  
  187.                         }  
  188.                 }  
  189.                 break;  
  190.   
  191.         case GLUT_RIGHT_BUTTON:  
  192.                 {  
  193.                         if (state == GLUT_DOWN) {  
  194.   
  195.                         }  
  196.                 }  
  197.                 break;  
  198.   
  199.         default:  
  200.                 break;  
  201.         }  
  202. }  
  203.   
  204.   
  205. void mouseMove(int x, int y)  
  206. {  
  207.         if(mouseLeftDown)  
  208.         {  
  209.                 yRot += (x - mouseX);  
  210.                 xRot += (y - mouseY);  
  211.                 mouseX = (float)x;  
  212.                 mouseY = (float)y;  
  213.         }  
  214.         glutPostRedisplay();  
  215. }  
  216.   
  217.   
  218. void mouseWheel(int wheel, int direction, int x, int y)  
  219. {  
  220.         switch (direction)  
  221.         {  
  222.   
  223.         case 1: //means wheel up  
  224.                 {  
  225.                         zoom -= 1.0f;  
  226.                 }  
  227.                 break;  
  228.   
  229.         case -1: //means wheel down  
  230.                 {  
  231.                         zoom += 1.0f;  
  232.                 }  
  233.                 break;  
  234.   
  235.         default:  
  236.                 break;  
  237.         }  
  238.         glutPostRedisplay();  
  239. }  
  240.   
  241.   
  242. void keyboard(unsigned char key, int x, int y)  
  243. {  
  244.         switch(key)  
  245.         {  
  246.         case 27: // ESCAPE  
  247.                 exit(0);  
  248.                 break;  
  249.   
  250.         default:  
  251.                 break;  
  252.         }  
  253.   
  254. }  
  255.   
  256.   
  257. void idle()  
  258. {  
  259.         glutPostRedisplay();  
  260. }  
  261.   
  262.   
  263. int main(int argc, char** argv)  
  264. {  
  265.         glutInit(&argc, argv);  
  266.         glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);  
  267.         glutInitWindowSize(640, 480);  
  268.         glutCreateWindow(argv[0]);  
  269.         if (glewInit()) {  
  270.                 std::cerr << "Unable to initialize GLEW ... exiting" << std::endl;  
  271.                 exit(EXIT_FAILURE);  
  272.         }  
  273.         init();  
  274.         glutDisplayFunc(display);  
  275.         glutReshapeFunc(reshape);  
  276.         glutMouseFunc(mouse);  
  277.         glutMotionFunc(mouseMove);  
  278.         glutMouseWheelFunc(mouseWheel);  
  279.         glutKeyboardFunc(keyboard);  
  280.         glutIdleFunc(idle);  
  281.         glutMainLoop();  
  282. }  
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值