将负值混合到帧缓冲区 0 opengl
Posted
技术标签:
【中文标题】将负值混合到帧缓冲区 0 opengl【英文标题】:Blend negative value into framebuffer 0 opengl 【发布时间】:2019-02-25 20:05:05 【问题描述】:程序将一堆东西渲染到一个中间帧缓冲区中,该缓冲区使用无符号规范化纹理来存储数据。中间帧缓冲区与默认帧缓冲区混合。用于渲染与帧缓冲区 0 混合的中间体的像素着色器如下:
#version 300 es
precision mediump float;
out vec4 fragColor;
in vec2 texCoords;
uniform sampler2D textureToDraw;
void main()
vec4 sampleColor = texture(textureToDraw, texCoords);
fragColor = vec4(sampleColor.rgb * -1.0, sampleColor.a);
设置draw到framebuffer 0的代码如下:
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
// Draw the intermediate using the pixel shader above and a quad
fragColor
的 rgb 分量将在 [-1, 0] 范围内。预期的结果是从先前的帧缓冲区内容中减去中间颜色。实际结果是黑色与帧缓冲区为 0 的正确 alpha 混合,这表明 fragColor
在某处被钳制为 [0, 1] 并且负部分被丢弃。
有没有办法禁用片段着色器输出到 [0, 1] 的钳位?
我知道没有办法渲染到已签名的规范化纹理,因此可能存在 OpenGL 限制来阻止这种情况。我正在考虑的替代方案是进行两次渲染,一次将负位渲染到中间,另一个将正位渲染到另一个中间。最后,将正面与GL_FUNC_ADD
混合,将负面与GL_FUNC_REVERSE_SUBTRACT
混合。维护起来既慢又麻烦。有没有其他办法?
【问题讨论】:
【参考方案1】:有没有办法禁用片段着色器输出到 [0, 1] 的钳位?
让我引用OpenGL 4.6 Core Profile Specification 的17.3.6 混合部分(强调我的):
如果颜色缓冲区是定点的,则 源值 和目标值以及混合因子的分量分别被限制为 [0, 1] 或 [−1, 1] 以用于无符号在评估混合方程之前进行归一化或有符号归一化颜色缓冲区。 如果颜色缓冲区是浮点数,则不会发生钳位。 结果 四个值被发送到下一个操作。
因此您可以使用*16F
或*32F
格式之一来摆脱钳制。
我知道没有办法渲染到已签名的规范化纹理,因此可能存在 OpenGL 限制来阻止这种情况。
规范将各种_SNORM
标记为颜色可渲染。但是,与此同时,规范并没有将这些格式标记为 必需 以支持渲染目标,因此实现 可以 允许您使用这种格式,但是他们不必,所以是的,你不能以任何方式依赖它......
【讨论】:
感谢您提供这些详细信息!渲染到浮点纹理按预期工作并保留符号。不过,在与默认帧缓冲区混合之前,看起来负值仍然被限制。有没有办法将默认帧缓冲区的内部格式也设置为浮点数? 格式支持取决于操作系统,但当今大多数设备上的显示表面不太可能理解浮点(除非您有 HDR 面板,否则它没有多大意义)。 对于 OpenGL ES 还请注意,浮点渲染仅在 ES 3.2 中是强制性的,因此仅适用于较新的设备。另请注意,它非常占用内存带宽(每像素更多位,并不总是得到表面压缩),因此虽然您可以做到这一点,但对于整体应用程序效率而言,这可能不是一个好主意。 我最终将场景中的图层分组为可组合的块,这些块被混合在一起形成一个浮点中间体。它们被组织在树中,以便子可组合块混合到父中间块中。由于 OpenGL 不会在用于浮点纹理的混合上限制负值,因此可以按预期工作。渲染到默认帧缓冲区时,负值按预期被钳位,此时就可以了。以上是关于将负值混合到帧缓冲区 0 opengl的主要内容,如果未能解决你的问题,请参考以下文章