【问题标题】:How to render into different layers and then combine them together with OpenGL?如何渲染成不同的层,然后用OpenGL将它们组合在一起?
【发布时间】:2013-10-04 06:41:04
【问题描述】:

我正在渲染几个图层,不能只在一个帧缓冲区上渲染,因为修改会影响它下面的所有其他图层。

如何分别渲染这些图层,以便将它们组合成一个最终图层?图层将被渲染为透明,因此在组合它们时,它们将相应地混合到下面的所有图层。

我目前正在使用 FBO 将它们全部渲染到一个层中,但正如我上面所说,当最顶层也影响所有底层时,它不会很好地工作。

那么,我如何才能尽可能高效地将两个(或更多?(无论哪种方式更快))FBO(或更好的 FBO 方法?)组合在一起?目前我可以将它们一个一个渲染,放入我的 RAM,然后我自己按像素组合它们,但这似乎是一种缓慢的方法。

最快的方法是什么?

【问题讨论】:

    标签: c++ opengl


    【解决方案1】:

    使用 2D 纹理数组。数组的每一层都是一个渲染层。

    将每一层渲染成自己的颜色附件纹理层(可以随时切换FBO颜色附件),使用glFramebufferTexture3D可以选择目标层。

    然后在片段着色器中根据需要组合 2D 阵列纹理的层。

    您还可以通过将不同的纹理层绑定到不同的渲染目标来使用多渲染目标。

    【讨论】:

    • 真的有必要把所有层同时保存在内存中吗?不能只分配两个缓冲区,然后每次将新缓冲区合并到第一个缓冲区,直到不再需要渲染层,因此第一个缓冲区将包含结果图像?例如,8 层将使用我的 GFX 卡内存的 50%(2048x2048x4 大小的缓冲区)。
    • @Rookie:您当然可以在foreach(layer) {render layer; composite layer into destination} 循环中进行渲染。但是,这会为每个合成设置一个同步点,因此整体性能可能会下降。
    【解决方案2】:

    您可以使用 MRT(多个渲染目标)。您将需要创建和绑定帧缓冲区(似乎您已经知道该怎么做),然后将几个纹理附加到它上,就像

    glFramebufferTexture2DEXT ( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texA, 0 );
    glFramebufferTexture2DEXT ( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, texB, 0 );
    

    在这里我附加了两个纹理(texAtexB,它们是使用glGenTextures 创建的),作为颜色附件编号01。然后,您只需在着色器中编写颜色,而不是使用gl_FragColor 输出变量,而是使用gl_FragData[0] 作为第一个颜色附件,gl_FragData[1] 作为第二个颜色附件。

    然后,您可以使用第二遍来组合存储在 texAtexB 纹理中的图像。

    附:这些是 OpenGL 2 的函数调用。如果您使用 OpenGL 3,函数调用是相似的(只是没有EXT),但您需要手动为着色器指定输出。如有必要,我可以发布解决方案。

    【讨论】:

    • 所以这种方法需要我为每个层数分别创建一个着色器?在我的情况下,层的数量是可变的。没有着色器这可能吗?我在想类似的事情,使用两个缓冲区,每次都将第二个缓冲区与第一个缓冲区结合起来,所以最后第一个缓冲区就是结果图像。
    • 正如您在问题中已经提到的,这将是一种缓慢的方法。着色器是进行复杂计算或效果的常用方法,因此最好使用它们。在现代图形 API(自 OpenGL 3 起)中,您甚至需要着色器来渲染简单的三角形,因此最好熟悉它们。
    • 关于着色器的可变数量:最好的方法是为每个层数编写单独的着色器(即一个着色器用于 2 层,一个着色器用于 3 层等)。另一种方法是使用条件if 在一个着色器中编写它。我不能说哪一个会更快,所以我建议尝试一下,但请记住,在着色器中使用条件并不是最佳实践(GPU 不是为通用计算设备而设计的,它们运行速度很慢处理条件跳转)
    • 我更担心内存消耗,因为这个程序可以在多个进程中同时运行。你知道如果我只使用 2 个缓冲区会慢多少吗?关于可变数量的着色器;我想我可以通过在运行着色器之前生成着色器代码来做到这一点,我想它只需要在代码中重复一些,所以它不应该太难。但是,正如我所说,我更担心这里的内存使用。
    • 动态生成着色器代码可能是个好主意,但最好将一些常用案例放在单独的着色器中,以节省编译它们所需的时间。然后,如果您遇到非常罕见的情况,您可以修改着色器代码并编译它,但大多数时候您将拥有一个已经编译好的着色器。至于内存消耗,您可以随时使用 gDebugger 进行检查。我对 GPU 的内存分析没有任何经验,所以我不知道可能的内存瓶颈
    【解决方案3】:


    也许我错了,但是您可以创建按级别排序的图层管理。然后,您只需将第一层绘制到最后一层,如果您有正确的混合功能,就可以实现所需的 alpha 效果……此外,您可以控制所有场景的总 alpha。清除 DEPTH BIT BUFFER 以独立渲染每一层是很重要的。

    这个想法的一点伪代码可以如下,

    Total Alpha = 0.9
    For l in layer_list // render layers
        // clear depth bit (important before render every layer)
        glClear(GL_DEPTH_BIT_BUFFER)   
    
        // render all objects layer of layer 'l' with alpha = layer_alpha * total_alpha
        renderLayer(l, TotalAlpha*l.getAlpha())
    
    End For
    

    【讨论】:

    • 我已经尝试过了,不幸的是没有成功...由于某种原因,有些对象根本不会渲染,不知道为什么。
    猜你喜欢
    • 2018-03-06
    • 1970-01-01
    • 1970-01-01
    • 2020-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多