【问题标题】:Writing OpenEXR 16bit image file in C++用 C++ 编写 OpenEXR 16 位图像文件
【发布时间】:2014-11-04 22:10:37
【问题描述】:

我正在尝试使用 OpenEXR 编写使用 OpenGL 渲染的 16 位纹理,遵循 the example in page 4 from the documentation,但由于某种原因,我的代码在执行 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);

【问题讨论】:

    标签: c++ image opengl 16-bit openexr


    【解决方案1】:

    您是否只是复制并粘贴了该代码(并且只是该代码)?那么它失败的原因是:

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

    改为这样做:

    首先是一个helper,用来清理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 操作之后立即被映射,这使得整个事情同步。

    【讨论】:

    • 当然,此时我已经正确设置了 fboIdpboId,并且我还会在创建和填充它们时检查错误,尽管我应该在我的题。我认为这可能与GL_HALF_FLOAT_NV 支持有关...我将在今天晚些时候再次检查。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2016-11-11
    • 1970-01-01
    • 2011-01-26
    • 2015-12-13
    • 2012-09-30
    • 1970-01-01
    • 1970-01-01
    • 2012-05-30
    相关资源
    最近更新 更多