前略好几章都没放上来,以后再补上吧。
之前一直使用gltools的GLBatch来填充数据传给shader,现在直接用自己的buffer来传数据了。
不外乎几步:
unsigned int n = 1;
GLuint buffers[n];
glGenBuffer(n, buffers);
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); // 当然想写成*buffers也可以
上面提及这种类型就是可以拿来放顶点啊,颜色啊,纹理坐标啥的。glDeleteBuffers(1, buffers);
另外,怎么传输数据是个问题。
glBufferData(GL_PIXEL_PACK_BUFFER, dataSize, data, GL_DYNAMIC_COPY);
第一个参数是绑定点(what?),第二个参数是用途。
不知道用啥的时候就用GL_DYNAMIC_DRAW。
使用glBufferData之后原来缓冲区的所有东西会被删除,重新进行填充。
如只想更新部分数据而不清空旧有,可以使用
void glBufferSubData(GLenum target, intptr offset, sizeiptr size, const void data*);
为啥使用缓冲区。
在使用缓冲区的时代之前,要向OpenGL传递纹理需要通过CPU先把内容复制到ram,再在需要的时候,命令CPU把内容从RAM传给OpenGL。坏处有二:
使用缓冲区之后,这一过程变成了:CPU把内容交给PBO,而PBO是OpenGL管理的(也即是GPU管理),在需要的时候OpenGL直接通过DMA(直接存取)来读取PBO,不需要经过CPU。这就是异步过程,不影响CPU周期。
图如下:
以上均整理自:http://www.songho.ca/opengl/gl_pbo.html
关于pack和unpack。
在GL_PIXEL_PACK_BUFFER模式下时,使用glReadPixels可以从帧缓存读取像素写到pbo。
在GL_PIXEL_UNPACK_BUFFER模式下,使用glDrawPixels把像素从pbo写入帧缓存。
使用void* glMapBuffer(target, access)
可以获得地址,如果找不到会返回nullptr。
target可能的值有:
access可能的值:
如果GPU正在操作这个buffer,glMapBuffer就会一直等待直到GPU同步完buffer信息。为了避免这个无用的等待,最好就是使用空指针来调用glBufferData,这会让这块空内存上啥都没有,然后马上调用glMapBuffer。这时,OpenGL会丢弃老的buffer,然后重新分配一块新的内存给它。
注意:
在使用完pbo之后,必须调用glUnmapBuffer(),如果成功了,会返回一个GL_TRUE。
在分配的时候没啥要注意的,如果是为纹理分配,那分配的空间就是长*宽*像素大小。
从当前帧获取像素数据,使用glReadPixels。
不使用pbo:
void *data = (void*)malloc(pixelDataSize);
glReadBuffer(GL_BACK_LEFT);
glReadPixels(0, 0, GetWidth(), GetHeight(), GL_RGB, GL_UNSIGNED_BTYE, pixelData);
使用pbo:
glReadBuffer(GL_BACK_LEFT);
glBindBuffer(GL_PIXEL_PACK_BUFFER, pixBuffObjs[0]);
glReadPixels(0, 0, GetWidth(), GetHeight(), GL_RGB, GL_UNSIGNED_BYTE, NULL);
这就把数据读入了pbo。
使用pbo来做模糊效果。思路是存储前面五帧来和当前帧做混合。
说一下主要套路:
// 这个时候啥功能都可以,pack或者unpack都行
glBindBuffer(GL_PIXEL_PACK_BUFFER, g_bufferObjs[0]);
glBufferData(GL_PIXEL_PACK_BUFFER, size, dataPtr, GL_DYNAMIC_DRAW);
// 解绑
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
glBindBuffer(GL_PIXEL_PACK_BUFFER, g_bufferObjs[0]);
glReadPixels(0, 0, screenWidth, screenHeight, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
glBindBuffer(GL_PIXEL_PACK_BUFFER, *g_bufferObjs);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, *g_bufferObjs);
glActiveTexture(GL_TEXTURE0 + GetBlurTarget0());
// 当数据是nullptr的时候,就读缓冲区~
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, screenWidth, screenHeight, 0, GL_UNSIGNED_BYTE, NULL);