我很想问一个简洁的问题,可以得到一个明确的答案,但我担心关于 FBO 初始化有太多我不完全理解的小事情需要澄清。我正在编写一个针对 OpenGL 4.3 和 OpenGL ES 3.0 的延迟着色器,前者的行为完全符合我的预期,但后者给了我无法识别来源的问题。
首先,我将描述我对为 GL 4.2 和 ES 3.0 设置 MRT FBO 的理解/困惑,并希望有人能够纠正任何误解。
OpenGL ES 3.0 规范说它支持“四个或更多渲染目标”,但没有提及(我能找到)这些渲染目标的规范。对这些渲染目标的大小有什么安全的假设?我可以简单地假设它可以具有
RGBA32F
(四个 32 位浮点通道)的内部格式吗?在我看来,这是着色器写入 RT 的关键假设/知识。是否通用程序:尝试创建具有特定规范的 FBO,然后测试 FBO 的完整性?如果失败:减少要求并使用替代着色器来补偿减少的位深度?精度限定符据说“有助于 OpenGL ES 的代码可移植性,并且对常规 OpenGL 没有影响”,但我发现很难理解这些
highp
,mediump
,lowp
, 到底是做什么用的,以及它们如何与渲染目标。首先,我假设渲染目标的位深度是在 FBO 中确定和配置的,并且精度限定符会自动匹配这个,这让我认为high
,medium
并且与深度位有low
某种关系。我已经看过了,这并不是很清楚。32
16
8
OpenGL ES 3.0 specs
FBO 的纹理附件是使用
glTexStorage2D
(withtarget=GL_TEXTURE_2D
,levels=1
) 配置的,我认为在这里使用它比 更正确glTexImage2D
,因为只有internalformat
应该重要。COLOR_ATTACHMENT
然后使用(3.) 将配置的纹理附加到 FBOglFramebufferTexture2D
。
它变得奇怪的地方(packHalf2x16
/ unpackHalf2x16
):
假设我为 FBO 设置了两个颜色附件,第一个 ( RT1
) 带有 internalformat GL_RGBA32UI
,第二个 ( RT2
) 带有GL_RGBA32F
. 对象分两次渲染。第一个是 FBO 的 RT,然后是两个由默认帧缓冲区处理的全屏四边形。
为简化起见,我将只关注在两个阶段之间传递 RGB 颜色数据。我试图以三种不同的方式这样做:
[适用于 GL 和 ES]使用
RT2
, 将颜色数据定期存储为浮点数,将其读取为浮点纹理并将其输出到默认帧缓冲区。[适用于 GL 和 ES]使用
RT1
,存储转换为uint
(在[0,..,255]
每个通道中)的颜色数据,将其作为uint
纹理读取,将其转换为浮点数[0,1]
并将其输出到默认帧缓冲区。[仅适用于 GL]使用
RT1
,将颜色数据打包到一个半通道中,使用packHalf2x16
. 将其作为uint
纹理读取,然后使用unpackHalf2x16
.
不确定代码细节的相关性/重要性(我会迅速跟进任何请求)。我highp
同时使用float
和int
。第一遍的渲染目标定义为:
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
中,桌面 GL 输出如下所示:
在 Nexus 5 上,方法1
和2
OpenGL ES 3.0 输出如下所示:
然而,nexus 5 上的方法3
如下所示:
我无法弄清楚为什么第三种方法在 OpenGL ES 3.0 上失败。任何帮助或建议将不胜感激。我并不反对阅读文档,所以如果您只想为我指明正确的方向,那也会有所帮助。