WebGL中透明纹理的行为

23

环境: WebGL,Chrome。当我将透明PNG作为模型的纹理时,出现以下行为:

  1. 图像A - 树遮挡了它后面的建筑物,我看到了世界盒子纹理。它也隐藏了自身(背部树枝不可见)
  2. 同时 - 图像B - 正常工作,窗户是透明的,我可以看到后面的东西

A: Tree over house B: Window transparency

两个截图在同一场景中从不同的摄像机位置拍摄而成。纹理由相同算法生成。

我无法理解窗户和树枝的透明度之间的区别。我的主要问题是 - 如何修复树枝,使其不会隐藏在其后面的对象?Shader代码如下:

gl_FragColor = vec4(textureColor.rgb * vLightWeighting, textureColor.a);

我尝试过启用/禁用混合和深度测试,有时可以得到所需的结果,但不确定这是否是正确的做法。

3个回答

38

你遇到了深度缓冲区问题,这与你的着色器或混合模式无关。

发生这种情况是因为你渲染透明几何体的顺序影响了你在其后面进行渲染的能力。这是因为深度缓冲区没有透明或不透明的概念。因此,即使它们在视觉上不对场景产生贡献,那些透明像素也会被写入深度缓冲区,之后你在它们后面绘制的任何像素都会被丢弃,因为它们“不可见”。但是,如果您先绘制透明对象后面的几何体,则会正确显示,因为它在透明深度被放置以丢弃它之前就被写入帧中。

即使是大型商业游戏引擎在某种程度上仍然难以解决这个问题,所以不要因此感到沮丧。 :)

没有“完美的解决方案”来解决这个问题,但实际上它归结为尝试按以下方式组织场景:

  1. 通过状态(着色器/纹理等)对任何不透明的几何体进行排序
  2. 接下来绘制任何透明的几何体。如果可能,按深度对它们进行排序,以便首先绘制最远离相机的对象。

通过标记透明几何体的位并在所有其他几何体之后渲染它们,你将解决90%的这个问题,但是对于重叠的透明对象可能仍然存在问题。这可能不是您的问题,具体取决于您的场景,但如果仍然会导致伪影,则需要在绘制之前按深度对透明对象进行排序。


感谢您清晰的答复。我可以按照要求进行渲染。那么唯一剩下的问题就是自我重叠。在示例中,树将后面的分支“隐藏”在前面。假设无法通过常规方法解决。至少现在已有90%的问题通过正确顺序的渲染得到了解决。 - Vecnas
@Toji 有没有一种好的方法可以按深度对对象进行排序?问候 - schlenger

7

如果丢弃透明度低于0.5的片段,可能会有帮助(当然,会有副作用)。

if(gl_FragColor.a < 0.5) discard;

WebGL中的AlphaFunctions?


0

我是一个WebGL的新手,对于图形处理也不是很熟悉。但是理论上,在每次迭代中调用drawElements两次或多次可能也可以解决问题吗? 还有一篇关于字体几乎相同问题的文章,作者通过设置参数{alpha:false}来解决它。 对我来说这没有意义,但它确实有效。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接