OpenGL深度测试和混合不同步

2022-03-01 00:00:00 opengl c++ glsl blending 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);
            }
然后我将其放入格式为GL_RED的GL_TEXTURE_2D中。在片段着色器(通过glDrawArraysInstanced)中,我按如下方式绘制粒子:

color = vec4(ParticleColor.rgb, texture(Sampler, UV).r);

这可以正常工作,生成如下图片(放大的粒子用于演示):

如您所见,没有任何人工制品。这里的每个粒子都是相同大小的,所以您在较大的粒子上看到的每个较小的粒子都在背景中,应该看不到。当我使用

打开深度测试时
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);

我得到如下内容:

因此,这在很大程度上看起来是正确的(&q;较小&q;粒子位于&q;较大&q;粒子后面)。但我现在有了底层四合院的文物。奇怪的是,并不是所有的粒子都有这种行为。

谁能告诉我,我做错了什么?还是深度测试和混合不能很好地配合?

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

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


解决方案

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

color = vec4(ParticleColor.rgb, texture(Sampler, UV).r);
if (color.a == 0.0)
    discard;

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

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

相关文章