OpenGL 深度测试和混合不能同时工作

Pau*_*ner 5 c++ opengl blending glsl depth-testing

我目前正在编写重力模拟,并且在使用 OpenGL 显示粒子时遇到一个小问题。

为了获得“圆形”粒子,我创建了一个小的浮点数组,如下所示:

for (int n = 0; n < 16; n++)
            for (int m = 0; m < 16; m++)
            {
                AlphaData[n * 16 + m] = ((n - 8) * (n - 8) + (m - 8) * (m - 8) < 64);
            }
Run Code Online (Sandbox Code Playgroud)

然后我将其放入格式为 GL_RED 的 GL_TEXTURE_2D 中。在片段着色器中(通过 glDrawArraysInstanced),我像这样绘制粒子:

color = vec4(ParticleColor.rgb, texture(Sampler, UV).r);
Run Code Online (Sandbox Code Playgroud)

这可以正常工作,生成这样的图片(为了演示而放大了粒子):

在此输入图像描述

如您所见,没有任何伪影。这里的每个粒子都具有相同的大小,因此您在“较大”粒子上看到的每个较小的粒子都位于背景中,不应该是可见的。当我打开深度测试时

glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
Run Code Online (Sandbox Code Playgroud)

我得到这样的东西: 在此输入图像描述

因此,在大多数情况下,这看起来是正确的(“较小”的颗粒位于“较大”颗粒的后面)。但我现在有了来自底层四边形的工件。奇怪的是并非所有粒子都有这种行为。

谁能告诉我,我做错了什么?或者深度测试和混合不能很好地协同工作?

我不确定您可能还需要哪些其他代码来进行诊断(其他一切似乎都工作正常),所以如果您需要其他代码,请告诉我。

我在这里使用透视投影(当然对于 3D 空间中的粒子)。

BDL*_*BDL 4

您处于一种特殊情况,您的片段要么完全不透明,要么完全透明,因此可以同时进行深度测试和混合。实际的问题是,对于深度测试,即使是完全透明的片段也会存储其深度值。您可以通过显式丢弃着色器中的片段来阻止写入。就像是:

color = vec4(ParticleColor.rgb, texture(Sampler, UV).r);
if (color.a == 0.0)
    discard;
Run Code Online (Sandbox Code Playgroud)

请注意,条件分支可能会带来一些额外的开销,但我预计您的情况不会出现太多问题。

对于半透明片段的一般情况,同时进行混合和深度测试是行不通的。为了使混合产生正确的结果,您必须在渲染之前对几何体进行深度排序,并从后到前进行渲染。