OpenGL 深度测试和混合不能同时工作
OpenGL depth testing and blending not working simultaniously
我目前正在编写重力模拟,但在使用 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);
我得到这样的结果:
所以在大多数情况下,这看起来是正确的(“较小”的粒子在“较大”的粒子后面)。但我现在有来自底层四边形的工件。奇怪的是,并不是所有的粒子都有这种行为。
谁能告诉我,我做错了什么?或者深度测试和混合不能很好地协同工作?
我不确定,您可能还需要哪些其他代码来进行诊断(其他一切似乎都可以正常工作),所以请告诉我,如果您需要其他代码。
我这里使用的是透视投影(当然是3D粒子-space)。
您处于一种特殊情况,您的片段要么完全不透明,要么完全透明,因此可以同时进行深度测试和混合。实际问题是,对于深度测试,即使是完全透明的片段也会存储它的深度值。您可以通过显式丢弃着色器中的片段来防止写入。类似于:
color = vec4(ParticleColor.rgb, texture(Sampler, UV).r);
if (color.a == 0.0)
discard;
请注意,条件分支可能会带来一些额外的开销,但我预计您的情况不会出现太多问题。
对于半透明片段的一般情况,同时进行混合和深度测试是行不通的。为了混合产生正确的结果,您必须在渲染之前对几何体进行深度排序,并从后向前渲染。
我目前正在编写重力模拟,但在使用 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);
我得到这样的结果:
所以在大多数情况下,这看起来是正确的(“较小”的粒子在“较大”的粒子后面)。但我现在有来自底层四边形的工件。奇怪的是,并不是所有的粒子都有这种行为。
谁能告诉我,我做错了什么?或者深度测试和混合不能很好地协同工作?
我不确定,您可能还需要哪些其他代码来进行诊断(其他一切似乎都可以正常工作),所以请告诉我,如果您需要其他代码。
我这里使用的是透视投影(当然是3D粒子-space)。
您处于一种特殊情况,您的片段要么完全不透明,要么完全透明,因此可以同时进行深度测试和混合。实际问题是,对于深度测试,即使是完全透明的片段也会存储它的深度值。您可以通过显式丢弃着色器中的片段来防止写入。类似于:
color = vec4(ParticleColor.rgb, texture(Sampler, UV).r);
if (color.a == 0.0)
discard;
请注意,条件分支可能会带来一些额外的开销,但我预计您的情况不会出现太多问题。
对于半透明片段的一般情况,同时进行混合和深度测试是行不通的。为了混合产生正确的结果,您必须在渲染之前对几何体进行深度排序,并从后向前渲染。