我必须在 OpenGL 中渲染屏幕外,然后将图像传递给 QImage。另外,为了练习,我想将深度和模板缓冲区也传输到 CPU。
为了在屏幕外绘制,我使用了带有渲染缓冲区的帧缓冲区对象(而不是纹理,因为我不需要纹理)。
使用颜色缓冲区(实际的原始图像)进行像素传输操作。我明白了我的期望。但是深度和模板不起作用..深度的奇怪图像和模板没有任何关系。
首先,简单的部分,我实际绘制的内容:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(-1.5f,0.0f,-6.0f);
glBegin(GL_TRIANGLES);
glColor3f(1.0f,0.0f,0.0f);
glVertex3f( 0.0f, 1.0f, 0.0f);
glColor3f(0.0f,1.0f,0.0f);
glVertex3f(-1.0f,-1.0f, -1.0f);
glColor3f(0.0f,0.0f,1.0f);
glVertex3f( 1.0f,-1.0f, 0.0f);
glEnd();
这里是 FBO 和 3 渲染缓冲区的初始化:
// frame buffer object
glGenFramebuffers(1, &fboId);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
// render buffer as color buffer
glGenRenderbuffers(1, &colorBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
// attach render buffer to the fbo as color buffer
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBuffer);
// render buffer as depth buffer
glGenRenderbuffers(1, &depthBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
// attach render buffer to the fbo as depth buffer
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);
glGenRenderbuffers(1, &stencilBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, stencilBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
// attach render buffer to the fbo as stencil buffer
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_BUFFER, GL_RENDERBUFFER, stencilBuffer);
最后,这里有 3 种像素传输方法:
QImage FBO::getImage()
{
// this is called Pixel Transfer operation: http://www.opengl.org/wiki/Pixel_Transfer
uchar *pixels;
pixels = new uchar[width * height * 4];
for(int i=0; i < (width * height * 4) ; i++ ) {
pixels[i] = 0;
}
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glReadPixels( 0,0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
QImage qi = QImage(pixels, width, height, QImage::Format_ARGB32);
qi = qi.rgbSwapped();
return qi;
}
QImage FBO::getDepth()
{
// this is called Pixel Transfer operation: http://www.opengl.org/wiki/Pixel_Transfer
uchar *pixels;
pixels = new uchar[width * height * 4];
for(int i=0; i < (width * height * 4) ; i++ ) {
pixels[i] = 0;
}
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
glReadPixels( 0,0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, pixels);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
QImage qi = QImage(pixels, width, height, QImage::Format_ARGB32);
qi = qi.rgbSwapped();
return qi;
}
QImage FBO::getStencil()
{
// this is called Pixel Transfer operation: http://www.opengl.org/wiki/Pixel_Transfer
uchar *pixels;
pixels = new uchar[width * height * 4];
for(int i=0; i < (width * height * 4) ; i++ ) {
pixels[i] = 0;
}
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glBindRenderbuffer(GL_RENDERBUFFER, stencilBuffer);
glReadPixels( 0,0, width, height, GL_STENCIL_INDEX, GL_FLOAT, pixels);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
QImage qi = QImage(pixels, width, height, QImage::Format_ARGB32);
qi = qi.rgbSwapped();
return qi;
}
这里是 2 个屏幕截图(颜色和深度,使用模板我得到一个空的 QImage):
颜色一正是我正在绘制的(翻转但我认为这是正常的)。深度..我期待一个带有渐变灰色三角形的白色图像..肯定我在图像格式上犯了一些错误(GL_FLOAT
?)但我尝试了一些组合,这是最好的结果..紫罗兰色背景,里面有毛刺的颜色..和模板缓冲区..我期待黑色背景中有一个白色三角形轮廓但是..不知道为什么我什么都看不到..
编辑:
好的,永远不要单独使用模板缓冲区,所以我已经重构了一点。
声明 FBO 时:
// render buffer for both depth and stencil buffer
glGenRenderbuffers(1, &depthStencilBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthStencilBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
// attach render buffer to the fbo as depth buffer
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthStencilBuffer);
深度的像素转移:
QImage FBO::getDepth()
{
std::vector<uchar> pixels;
pixels.reserve(width * height*4);
for(int i=0; i < (width * height*4) ; i++ ) {
pixels.push_back(0);
}
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glBindRenderbuffer(GL_RENDERBUFFER, depthStencilBuffer);
glReadPixels( 0,0, width, height, GL_DEPTH24_STENCIL8, GL_UNSIGNED_BYTE, pixels.data());
glBindFramebuffer(GL_FRAMEBUFFER, 0);
std::vector<uchar> _pixels;
_pixels.reserve(width * height*4);
for(int i=0; i < (width * height*4) ; i++ ) {
uchar p_red = pixels[i];
uchar p_green = pixels[i+1];
uchar p_blue = pixels[i+2];
uchar p_stencil = pixels[i+3];
_pixels.push_back(p_red);
_pixels.push_back(p_green);
_pixels.push_back(p_blue);
_pixels.push_back(255); // alpha
}
QImage qi = QImage(_pixels.data(), width, height, QImage::Format_ARGB32);
//qi = qi.rgbSwapped();
return qi;
}
模板类似,但p_stencil
与 rgb 组件一起使用
.. 结果图像是深度和模板的黑色图像
编辑
感谢 Nicolas 的回答,我设法将渲染缓冲区用于深度和模板缓冲区,并提取深度组件以适应QImage::Format_ARGB32
以下代码:
QImage FBO1::getDepth()
{
// sizeof( GLuint ) = 4 byte
// sizeof( uchar ) = 1 byte
std::vector<GLuint> pixels(width * height);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glBindRenderbuffer(GL_RENDERBUFFER, depthStencilBuffer);
glReadPixels( 0,0, width, height, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, pixels.data());
glBindFramebuffer(GL_FRAMEBUFFER, 0);
std::vector<uchar> _pixels;
for(int i=0; i < (width * height) ; i++ ) {
GLuint color = pixels[i];
float temp = (color & 0xFFFFFF00) >> 8; // 24 bit of depth component
// remap temp that goes from 0 to 0xFFFFFF (24 bits) to
// _temp that goes from 0 to 0xFF (8 bits)
float _temp = (temp / 0xFFFFFF) * 0xFF;
_pixels.push_back((uchar)_temp);
_pixels.push_back((uchar)_temp);
_pixels.push_back((uchar)_temp);
_pixels.push_back(255);
}
QImage qi = QImage(_pixels.data(), width, height, QImage::Format_ARGB32);
qi = qi.rgbSwapped();
return qi;
}
.. 模板组件仍然存在一些问题(以下代码不起作用:它会产生故障图像):
QImage FBO1::getStencil()
{
// sizeof( GLuint ) = 4 byte
// sizeof( uchar ) = 1 byte
std::vector<GLuint> pixels(width * height);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glBindRenderbuffer(GL_RENDERBUFFER, depthStencilBuffer);
glReadPixels( 0,0, width, height, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, pixels.data());
glBindFramebuffer(GL_FRAMEBUFFER, 0);
std::vector<uchar> _pixels;
for(int i=0; i < (width * height); i++ ) {
GLuint color = pixels[i];
uchar temp = (color & 0x000000FF); // last 8 bit of depth component
_pixels.push_back(temp);
_pixels.push_back(temp);
_pixels.push_back(temp);
_pixels.push_back(255);
}
QImage qi = QImage(_pixels.data(), width, height, QImage::Format_ARGB32);
qi = qi.rgbSwapped();
return qi;
}