【问题标题】:How to use glReadPixels() to return resized image from FBO?如何使用 glReadPixels() 从 FBO 返回调整大小的图像?
【发布时间】:2012-10-12 11:07:47
【问题描述】:

简而言之:我需要一种快速的方法来调整缓冲区图像的大小,然后将像素返回给我以将它们保存到文件等中。

目前我首先使用 glReadPixels(),然后我自己通过像素来使用自己的 resize 函数调整它们的大小。

有什么方法可以加快调整大小,例如让 OpenGL 为我完成这项工作?我想我可以在启用 miplevel 和 mipmapping 的情况下使用 glGetTexImage(),但正如我之前注意到的,该功能在我的 GFX 卡上存在错误,所以我无法使用它。

我只需要一个 miplevel,可以是 1 到 4 之间的任何值,但不是全部,以节省一些 GPU 内存。那么是否可以只生成一个所需大小的 miplevel?

注意:我不认为我可以使用多重采样,因为我需要像素精确的渲染来进行模板测试,所以如果我使用多重采样渲染它,它会使像素变得模糊,并且模板测试会失败并且掩蔽和结果将不正确(AFAIK)。 编辑:我只想缩放颜色(RGBA)缓冲区!

【问题讨论】:

    标签: c++ opengl fbo render-to-texture mipmaps


    【解决方案1】:

    如果您有 OpenGL 3.0 或 EXT_framebuffer_blit 可用(很可能 - 自 2005 年左右以来的所有 nVidia 卡,自 2008 年左右以来的所有 ATI 卡都有它,甚至英特尔高清显卡都声称支持它),那么您可以 @ 987654321@ 放入一个较小的帧缓冲区(分别具有较小的矩形)并让显卡完成工作。
    请注意,即使您要说“我不需要原来的”,您也永远无法在同一个帧缓冲区内安全地重新缩放,因为重叠的 blit 是未定义的(允许,但未定义)。

    或者,您当然可以使用简单的缩小像素着色器(aniso decimation,如果您愿意)绘制一个全屏四边形。

    事实上,既然您在最后一段中提到了模板...如果您想要重新缩放的是 模板(或深度),那么您最明确地想要绘制一个全屏四边形着色器,因为否则它很可能不会给出所需的结果。通常,在这种情况下,人们会选择max 过滤器而不是插值(例如,什么合理、有意义的结果可以插值模板值 0 和值 10 给出 - 需要其他东西,例如“任何非零”或“样本区域的最大值”)。

    【讨论】:

    • 我不知道你所说的重新缩放模具是什么意思。基本上我只是希望在完成渲染后,我只需调用“glReadPixelsResized”函数即可平滑调整原始图像大小的 25%。该图像包含什么或如何制作并不重要;我只想正确缩小所有像素数据。我不想读取模板缓冲区,只想读取 RGBA 颜色。
    • OK 完美,然后glBlitFrameBuffer 就可以了。我对模板感到困惑,因为您在上一段中写了关于多重采样和模板的内容,所以我不确定您想要做的确切事情是什么(例如缩小颜色 模板?)。如果它只是你想要的颜色,一切都很好。
    • 这是否真的平滑地调整了它,就好像它是多重采样的?根据我的经验,GL_LINEAR 不会以这种方式调整图像大小,我必须先生成 mipmaps
    • 人们应该期望,将生成与缩小图像中的像素对应的矩形中的值的未加权平均值,因为这就是线性过滤。但是,该规范没有定义 确切 GL_LINEAR 在这里的含义(它仅定义它用于纹理缩小,其中它是 2x2 样本缩小)。就目前而言,实现可能很便宜并且只做最少的事情。无论如何,它不会与 MSAA 相同,因为 MSAA 中的样本通常会以随机方式旋转或抖动以隐藏伪影。
    • 在任何情况下,完美 下采样无论如何都不是微不足道的,例如here (part 2)。有许多不同复杂程度的技术,但没有一个在各个方面都真正优越——它们都有优点和缺点。
    【解决方案2】:

    创建所需目标大小的帧缓冲区,并使用完全调整大小的缓冲区大小的纹理四边形绘制源图像。然后使用 glReadPixels 读取调整大小的帧缓冲区内容。

    伪代码:

    unbind_texture(OriginalSizeFBOattachmentColorTex);
    
    glBindFramebuffer(OriginalSizeFBO);
    render_picture();
    
    glBindFramebuffer(TargetSizeFBO); // TargetSizeFBO used a Renderbuffer color attachment
    glBindTexture(OriginalSizeFBOattachmentColorTex);
    glViewport(TargetSize);
    render_full_viewport_quad_with_texture();
    
    glReadPixels(...);
    

    【讨论】:

    • 这是否真的平滑地调整了它,就好像它是多重采样的?根据我的经验,GL_LINEAR 不会以这种方式调整图像大小,我必须先生成 mipmaps
    • @Rookie:确实你必须以某种方式实现过滤。要么使用生成的 mipmap。或者你可以在它上面扔一个可以缩小的着色器。这将允许您使用比带有 mipmap 生成功能的 GL_LINEAR_MIPMAP_LINEAR 提供的简单双线性过滤更高级的过滤。
    • 我能不能以某种方式使用GL_GENERATE_MIPMAP,它只会为我生成一个特定的miplevel?这个着色器是如何制作的?我读取 x 和 y(+ 0 到 3)像素,取它们的平均值(通过使用 mix() w*h 次?)然后......以某种方式将其写入纹理?我不需要任何更高级的过滤,我只想取平均颜色,比如说 4x4 像素。
    • @Rookie:您可以使用 glGenerateMipmap(显式调用此函数),生成的 mipmap 级别由 GL_TEXTURE_BASE_LEVEL 和 GL_TEXTURE_MAX_LEVEL glTexParameter 值确定。关于着色器,是的,像您建议的这样的框过滤会起作用,但是您不会将其写入纹理,而只是在渲染到 FBO 时将其发送到 gl_FragColor 并且您将从那个中读取.
    • 好吧,如果我使用 glGenerateMipmap(),我可以调用一次,然后使用 glReadPixels() 来获取调整大小的像素?还是我需要设置 miplevel 的 glGetTexImage() ?所以我毕竟不需要着色器?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-29
    • 1970-01-01
    • 1970-01-01
    • 2021-04-25
    • 1970-01-01
    • 2011-01-24
    • 2011-03-05
    相关资源
    最近更新 更多