gpt4 book ai didi

c++ - 离屏渲染(使用 FBO 和 RenderBuffer)和颜色、深度、模板的像素传输

转载 作者:搜寻专家 更新时间:2023-10-31 00:38:41 26 4
gpt4 key购买 nike

我必须在 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):

enter image description here

enter image description here

颜色一正是我正在绘制的(翻转但我认为这是正常的)。深度..我期待一个带有渐变灰色三角形的白色图像..我肯定在图像格式上犯了一些错误(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;
}

模板类似,但使用带有 rgb 组件的 p_stencil

.. 结果图像对于深度和模板都是黑色图像

编辑

感谢 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;
}

最佳答案

The depth.. I'm expecting a white image with a gradient gray triangle..

您的代码不建议这样做。

uchar *pixels;
pixels = new uchar[width * height * 4];

这将创建一个整数 数组。这也是内存泄漏;使用 std::vector<uchar>相反。

glReadPixels( 0,0,  width, height, GL_DEPTH_COMPONENT, GL_FLOAT, pixels);

这告诉 OpenGL 将 float 写入您的整数数组。所以 OpenGL 会处理 pixels作为 GLfloat 的数组s 写作时。

QImage qi = QImage(pixels, width, height, QImage::Format_ARGB32);

我假设这会将其解释为某种每分量 8 位的整数 图像格式。所以你在解释 float s 为 8 位整数。没有理由期望这种行为是理性的。

您应该将深度缓冲区作为 float 读取并以更合理的方式将其转换为像素颜色,或者您应该将深度缓冲区作为整数值读取,让 OpenGL 为您进行灰度转换。

此外,您应该始终使用 combined depth/stencil image ,而不是两个单独的渲染缓冲区。


glReadPixels( 0,0,  width, height,  GL_DEPTH24_STENCIL8, GL_UNSIGNED_BYTE, pixels.data());

你似乎不明白pixel transfers工作。

首先,pixel transfer format指定您正在阅读的组件。它指定它们的大小。 GL_DEPTH24_STENCIL8an image format ,不是像素传输格式。如果你想从图像中读取深度和模板,你可以使用 GL_DEPTH_STENCIL .像素传输格式没有大小。

所以这个函数只是给你一个 OpenGL 错误。

大小来自第二个参数,pixel transfer type .在这种情况下 GL_UNSIGNED_BYTE意味着它将读取深度和模板,将每个转换为一个无符号的 8 位值,并将每个像素中的两个存储到 pixels.data() 中。 .

深度缓冲区每个像素仅存储 1 个值。深度/模板仅存储 2。您不能使用 OpenGL 将它们复制为每像素 4 个组件的格式。因此,无论您以后如何构建 QImage,它必须为每个像素采用 1 或 2 个值的方法。

一般来说,如果您想读取深度缓冲区,并且希望深度缓冲区的数据真正有意义,您可以这样做:

std::vector<GLuint> pixels(width * height);  //std::vector value-initializes its elements.

glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glReadPixels( 0,0, width, height, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, pixels.data());

如何将它们放入 QImage 中以进行可视化取决于您。但这会得到一个无符号整数数组,其中高 24 位是深度分量,低 8 位是模板。

关于c++ - 离屏渲染(使用 FBO 和 RenderBuffer)和颜色、深度、模板的像素传输,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17711673/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com