C++ OpenGL 4和ES 3.0与packHalf2x16/2x16不符

C++ OpenGL 4和ES 3.0与packHalf2x16/2x16不符,c++,opengl,opengl-es,glsl,glsles,C++,Opengl,Opengl Es,Glsl,Glsles,我很想问一个简洁的问题,让我有一个明确的答案,但我担心有太多关于FBO初始化的小事情我不完全理解,我需要澄清。我正在编写一个针对OpenGL 4.3和OpenGL ES 3.0的延迟着色器,前者的行为完全符合我的预期,但后者给了我无法确定问题来源的问题 首先,我将描述我对为GL 4.2和ES 3.0设置MRT FBO的理解/困惑,希望有人能够纠正任何误解 OpenGLES3.0规范说它支持“四个或更多的渲染目标”,但没有提到(我可以找到)这些渲染目标的规范。关于这些渲染目标的大小,可以安全地假设

我很想问一个简洁的问题,让我有一个明确的答案,但我担心有太多关于FBO初始化的小事情我不完全理解,我需要澄清。我正在编写一个针对OpenGL 4.3和OpenGL ES 3.0的延迟着色器,前者的行为完全符合我的预期,但后者给了我无法确定问题来源的问题

首先,我将描述我对为GL 4.2和ES 3.0设置MRT FBO的理解/困惑,希望有人能够纠正任何误解

  • OpenGLES3.0规范说它支持“四个或更多的渲染目标”,但没有提到(我可以找到)这些渲染目标的规范。关于这些渲染目标的大小,可以安全地假设什么?我是否可以简单地假设它的内部格式为
    RGBA32F
    (四个32位浮点通道)?在我看来,这是着色器编写到RTs的关键假设/知识。常见程序是:尝试创建具有特定规格的固定基地运营商,然后测试固定基地运营商的完整性?如果失败:减少要求并使用替代着色器来补偿减少的位深度

  • 精度限定符据说“有助于OpenGL ES的代码可移植性,对常规OpenGL没有任何影响”,但我发现很难理解这些
    highp
    mediump
    lowp
    究竟用于什么,以及它们如何与渲染目标的位深度一起发挥作用。首先,我假设渲染目标的位深度是在FBO中确定和配置的,并且精度限定符自动匹配这一点,这使我认为
    32
    16
    8
    深度位有某种关系。我已经看过了OpenGL ES 3.0规范,但还不是很清楚

  • FBO的纹理附件是使用
    glTexStorage2D
    (使用
    target=GL\u texture\u 2D
    levels=1
    )配置的,我认为在这里使用它比
    glTexImage2D
    更正确,因为只有
    internalformat
    才重要

  • 然后使用
    glFramebufferTexture2D
    将(3.)中配置的纹理附加到FBOs
    COLOR_附件


  • 奇怪的地方(
    packHalf2x16
    /
    unpackHalf2x16
    ): 假设我使用两种颜色附件设置FBO,第一种(
    RT1
    )使用internalformat
    GL_RGBA32UI
    ,第二种(
    RT2
    )使用
    GL_RGBA32F
    。对象在两个过程中渲染。第一个是FBOs RTs,然后两个是由默认帧缓冲区处理的全屏四元组

    为了简化,我将只关注在两个阶段之间传递RGB颜色数据。我尝试了三种不同的方式:

  • [适用于GL&ES]使用
    RT2
    ,将颜色数据定期存储为浮点,将其读取为浮点纹理,并将其输出到默认帧缓冲区

  • [适用于GL&ES]使用
    RT1
    ,存储转换为
    uint
    的颜色数据(每个通道在
    [0,…,255]
    中),将其读取为
    uint
    纹理,将其转换为float
    [0,1]
    ,并将其输出到默认帧缓冲区

  • [仅适用于GL]使用
    RT1
    ,使用
    packHalf2x16
    将颜色数据打包到一个半通道中。将其作为
    uint
    纹理读取,然后使用
    unpachalf2x16
    将其转换回float


  • 不确定代码细节的相关性/重要性(我将迅速跟进任何请求)。我对
    float
    int
    都使用了
    highp
    。第一个过程的渲染目标定义为:

    layout (location = 0) out uvec4 fs_rt1;
    layout (location = 1) out vec4 fs_rt2;
    
    在第二个过程中,作为纹理访问:

    uniform highp usampler2D RT1;
    uniform highp sampler2D RT2;
    ...
    
    // in main():
    uvec4 rt1 = texelFetch(RT1, ivec2(gl_FragCoord.xy), 0);
    vec4 rt2 = texelFetch(RT2, ivec2(gl_FragCoord.xy), 0);
    
    方法
    1.

    // in first pass:
    fs_rt2.rgb = decal.rgb;
    
    // in second pass:
    color = vec4(rt2.rgb, 1.0);
    
    方法
    2.

    // in first pass:
    fs_rt1.rgb = uvec3(decal.xyz * 256.0f);
    
    // in second pass:
    color = vec4(vec3(rt1.xyz)/256.0f, 1);
    
    方法
    3.

    // in first pass:
    fs_rt1.x = packHalf2x16(decal.xy);
    fs_rt1.y = packHalf2x16(vec2(decal.z, 0.0f));
    
    // in second pass:
    vec2 tmp = unpackHalf2x16(rt1.y);
    color = vec4(vec3(unpackHalf2x16(rt1.x), tmp.x), 1);
    

    在方法
    1
    2
    3
    中,桌面总账输出如下所示:

    在Nexus 5上,方法
    1
    2
    OpenGL ES 3.0输出如下所示:

    nexus 5上的方法
    3
    看起来如下:


    我不明白为什么第三种方法在OpenGLES3.0上失败。如有任何帮助或建议,将不胜感激。我并不反对阅读文档,因此如果您只想为我指出正确的方向,这也会有所帮助。

    关于前几个问题:

  • 您可以查询
    GL\u MAX\u COLOR\u ATTACHMENTS
    以获取可以附加到FBO的彩色附件的数量。对于ES 3.0,这保证大于4。这与颜色附件的格式无关(无论是渲染缓冲还是纹理)。但是,对于可以渲染到的格式有一些限制。请查看表格,特别是“颜色可渲染”列。这使您知道可以附加到FBO的格式。代码不需要测试FBO的完整性,但不是因为多个颜色附件。检查所有附件是否具有相同数量的样本和其他特定于供应商的内容,如深度/模板附件

  • GLE中有精度限定符来帮助优化。当您知道您正在处理某个范围内的数字时,某些算术运算在低精度下会更快或更有效,请参阅GLSL ES规范中的。请注意,这些是最小精度值,即使您请求低精度,一些供应商也会给您高精度。这些精度限定符仅在GLSL着色语言中有效。它不会影响渲染目标的格式