加权混合顺序无关透明度渲染问题

时间:2018-06-12 12:18:17

标签: opengl go transparency blending

我正在this article实施OIT方法,而我似乎无法根据他的reference image获得正确的结果。当我尝试重现他的参考(好吧,而不是完全)时,它会出现如下:

enter image description here

问题

因此,揭示输出看起来不错,但它的积累是完全错误的。首先,没有深度测试。蓝色和红色方块都应位于黄色方块的后面或前面。由于三个中间正方形都具有0.75个alpha值,因此也没有与黑色背景进行任何alpha混合。

然后在复合传递中,它似乎也没有使用揭示纹理来指示每个对象的深度。

从大多数OpenGL代码我可以看出,执行顺序是至关重要的,我在调试时(现在已经持续了三天),在移动诸如gl.DepthMask(false)或{之类的内容时会得到不同的结果{1}}向上一行。

代码

gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

在绘图函数的底部是我用来从我的测试参考中生成revealage和accumu图像的两个函数。

着色

以下是来自func (o *OpenGL) draw() { gl.ClearColor(clearColor.R, clearColor.G, clearColor.B, clearColor.A) gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) // DRAW OPAQUE FIRST (although the issue isn't really here, I just put it in incase) gl.BindFramebuffer(gl.FRAMEBUFFER, o.opaqueFBO) gl.DrawBuffer(gl.COLOR_ATTACHMENT0) gl.Enable(gl.DEPTH_TEST) gl.DepthMask(true) gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) gl.Disable(gl.BLEND) gl.UseProgram(o.opaqueShader) // Set uniforms // Draw opaque objects gl.UseProgram(0) // THEN TRANSPARENT gl.BindFramebuffer(gl.FRAMEBUFFER, o.transparentFBO) gl.DrawBuffers(2, &[]uint32{gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1}[0]) gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) gl.ClearBufferfv(gl.COLOR, 0, &[]float32{0, 0, 0, 1}[0]) gl.ClearBufferfv(gl.COLOR, 1, &[]float32{1, 1, 1, 1}[0]) gl.Enable(gl.DEPTH_TEST) gl.DepthMask(false) gl.Enable(gl.BLEND) gl.BlendFunci(0, gl.ONE, gl.ONE) gl.BlendFunci(1, gl.ZERO, gl.ONE_MINUS_SRC_ALPHA) gl.UseProgram(o.transparentShader) // Set uniforms // Draw opaque objects gl.UseProgram(0) // COMPOSITE PASS gl.BindFramebuffer(gl.FRAMEBUFFER, 0) gl.Disable(gl.DEPTH_TEST) gl.Disable(gl.BLEND) gl.UseProgram(o.compositeShader) gl.ActiveTexture(gl.TEXTURE0) gl.BindTexture(gl.TEXTURE_2D, o.transparentTex0) gl.Uniform1i(uniformLocation(o.compositeShader, "ColorTex0\x00"), int32(0)) gl.ActiveTexture(gl.TEXTURE1) gl.BindTexture(gl.TEXTURE_2D, o.transparentTex1) gl.Uniform1i(uniformLocation(o.compositeShader, "ColorTex1\x00"), int32(1)) gl.DrawElements(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, gl.PtrOffset(0)) gl.BindVertexArray(0) gl.UseProgram(0) // RENDER A SPECIFIC TEXTURE FROM A FRAMEBUFFER. FOR TESTING THIS DRAWS OVER WHAT HAS ALREADY BEEN DRAWN. // A. // o.renderFramebuffer(o.transparentFBO, o.transparentTex0) // B. // o.renderFramebuffer(o.transparentFBO, o.transparentTex1) } func (o *OpenGL) renderFramebuffer(fbo uint32, tid uint32) { // FBO DEBUGGER gl.BindFramebuffer(gl.FRAMEBUFFER, 0) gl.UseProgram(o.framebufferShader) gl.ActiveTexture(gl.TEXTURE0) gl.BindTexture(gl.TEXTURE_2D, tid) gl.Uniform1i(uniformLocation(o.framebufferShader, "Texture\x00"), int32(0)) // draw fullscreen quad gl.UseProgram(0) o.window.SwapBuffers() }

的片段着色器
o.transparentShader

来自#version 450 core layout(location=0) in vec2 vTexCoord; uniform vec4 uColor; layout(location=0, index=0) out vec4 oFragData0; layout(location=0, index=1) out vec4 oFragData1; float w(float z, float a) { return a * max( pow(10.0, -2.0), min( 3.0 * pow(10.0, 3.0), 10.0 / ( pow(10.0, -5.0) + pow(abs(z) / 5.0, 2.0) + pow(abs(z) / 200.0, 6.0) ) ) ); } void main() { vec4 Ci = uColor; float ai = Ci.a; float zi = gl_FragCoord.z; float wresult = w(zi, ai); oFragData0 = vec4(Ci.rgb * wresult, ai); oFragData1.r = ai * wresult; }

的片段着色器
o.compositeShader

最后的注释

我删除了所有错误检查以保持问题最小化。我可以确认在执行测试输出期间着色器,帧缓冲区附件或#version 450 core layout(location=0) out vec4 outColor; uniform sampler2D ColorTex0; uniform sampler2D ColorTex1; out vec4 oFragColor; void main() { vec4 accum = texelFetch(ColorTex0, ivec2(gl_FragCoord.xy), 0); float r = accum.a; accum.a = texelFetch(ColorTex1, ivec2(gl_FragCoord.xy), 0).r; vec4 transparentColor = vec4(accum.rgb / clamp(accum.a, 1e-4, 5e4), r); oFragColor = transparentColor * (1.0 - r); } 没有错误。

我还删除了与绘制不透明对象有关的大部分代码,因为这个问题与透明对象有关。

更新#1(没有帧缓冲区的测试)

作为一种绝望的行为,我已经删除了与FBO相关的所有代码,我发现了一些与混合相关的有趣结果......

启用DEPTH_TEST | BLEND禁用| DEPTH_MASK错误 enter image description here 禁用DEPTH_TEST |启用BLEND | DEPTH_MASK错误 enter image description here 已启用DEPTH_TEST |启用BLEND | DEPTH_MASK错误 enter image description here

听起来很荒谬,实际上看起来它可以分别进行混合和深度测试,但是当它结合起来时它只会做一点点然后放弃......这可能与混合有关功能

更新#2(基于NVidia参考的接近完美结果)

通过一些全新的调试工具以及对OIT如何工作的更好理解,我已经能够非常接近我希望的结果。最后的缺陷是不透明物体(缩放的黄色正方形和旋转的青色正方形)变暗。

enter image description here

通过调整BlendFunc值并学习一些关于何时使用其中每一对的一些重要课程,我做到了这一点:

  • gl.GetError() vs texture
  • texelFetch vs GL_TEXTURE_2D
  • GL_TEXTURE_RECT vs RGBA16F
  • RGBA vs ONE_MINUS_SRC_ALPHA

我强烈建议在尝试MRT,Framebuffers或OIT之前完全理解这些差异。每个引用都使用了这些值的不同组合。

更新#3(最终)

因此,在完全疏远所有引用并避免尝试复制代码之后,我查看了第一段中的参考图像,并按照自己的方式实现了它。

enter image description here

在我提交答案之前,我会暂时离开这个问题,因为我仍然有点怀疑,我想要进行更多的测试(或者听听你们的答案?)。

0 个答案:

没有答案