用C++编写OpenEXR 16位图像文件

Writing OpenEXR 16bit image file in C++

本文关键字:图像 文件 16位 OpenEXR C++ 编写      更新时间:2023-10-16

我正试图按照文档第4页中的示例,使用OpenEXR编写一个用OpenGL渲染的16位纹理,但由于某些原因,我的代码在执行file_exr.writePixels(512)时崩溃。这里有我遗漏的东西吗?

更新:我确实检查了fboIdpboId是否初始化良好,并且在此之前不存在OpenGL错误。

const Imf::Rgba * dest;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboId);                                            
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboId);
glReadPixels(0, 0, 512, 512,  GL_BGRA, GL_HALF_FLOAT_NV, 0);    
dest = (const Imf::Rgba *)glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
Imf::RgbaOutputFile file_exr("/tmp/file.exr", 512, 512, Imf::WRITE_RGBA);
file_exr.setFrameBuffer(dest, 1, 512);
file_exr.writePixels(512);
glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);

您刚才复制并粘贴了那个代码(以及那个代码)吗?那么它失败的原因是:

  • 要将OpenGL中的像素读取到的缓冲区对象不存在;因此,映射它将失败,这意味着您将OpenEXR指向一个空指针
  • 在上面的代码中根本并没有单一的错误条件检查

改为:

首先是一个助手,清理OpenGL错误堆栈(可能会累积多个错误条件):

int check_gl_errors()
{
    int errors = 0;
    while( GL_NO_ERROR != glGetError() ) { errors++; }
    return errors;
}

然后这个

int const width  = 512;
int const height = 512;
size_t const sizeof_half_float = 2;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboId);
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboId);
glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB,
      width * height * sizeof_half_float,
      NULL,
      GL_STATIC_READ_ARB);
if( !check_gl_errors() ) {    
    glPixelStorei(GL_PACK_ALIGNMENT, 1);
    glPixelStorei(GL_PACK_ROW_LENGTH, 0);
    glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
    glPixelStorei(GL_PACK_SKIP_ROWS, 0);
    /* BTW: You have to check that your system actually supports the
       GL_HALF_FLOAT_NV format extension at all. */
    glReadPixels(0, 0, width, width,  GL_BGRA, GL_HALF_FLOAT_NV, 0);
    if( !check_gl_errors() ) {
        Imf::Rgba const * const dest = (Imf::Rgba const*)
            glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
        if( !check_gl_errors() && nullptr != dest ) {
            Imf::RgbaOutputFile file_exr(
                "/tmp/file.exr",
                width, height,
                Imf::WRITE_RGBA);
            file_exr.setFrameBuffer(dest, 1, width);
            file_exr.writePixels(height);
            glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
        }
        else {
            /* glMapBuffer failed */
        }
    }
    else {
        /* glReadPixels failed */
    }
}
else {
    /* glBufferDataARB failed => no valid buffer object
       to work with in the first place */
}

所有这些错误检查都很重要。它们使你的程序不会崩溃,但会诊断出哪里出了问题。

无论如何,按操作顺序使用PBO无论如何都没有帮助,因为它在glReadPixels操作之后立即被映射,这使得整个操作同步。