使用GL_DEPTH_TEST和透明纹理渲染毛刺

时间:2012-02-19 21:02:58

标签: opengl 3d rendering depth

从一个角度看,我的灌木看起来像这样:

另一方面,它们看起来像这样:

我的理论是,当从第一个角度观察灌木时,灌木后面的所有块都已被抽出,所以当它来绘制灌木时,它只是将它们拉到上面。

然而,从另一个角度来看,它基本上是先尝试绘制灌木,然后当​​它去灌木丛后面的块时,它检查深度缓冲区并看到那里有什么东西已经阻挡了块的视图,因此它不会渲染它,导致海军蓝色方块(我的颜色清晰)。

我真的不知道如何解决这个问题。禁用深度测试会导致各种其他错误。有没有办法将顶点或多边形标记为具有透明度,以便它知道它仍然需要渲染后面的内容?


Found this。这是唯一的解决方案吗?要分离我的透明和不透明块,然后在CPU上手动对它们进行几乎每一帧的排序,因为玩家可以四处移动?必须有一种方法将其委托给GPU ...

3 个答案:

答案 0 :(得分:8)

该链接(以及在CPU上排序)用于alpha混合。如果您只需要Alpha测试(不是混合),那么您不需要对任何东西进行排序。只需启用alpha测试,启用深度测试,一切都将正常。

见这里:http://www.opengl.org/wiki/Transparency_Sorting 您需要需要进行alpha测试的“Alpha测试”,而不是需要排序的“标准半透明”。

答案 1 :(得分:3)

解决方案#1:

  1. 首先以任何顺序渲染所有非透明对象,启用深度缓冲区。这包括使用alpha测试的所有对象没有 alpha混合。
  2. 对于glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)个对象(烟雾/玻璃/草):将最远多边形的透明场景渲染到最近的多边形,并禁用深度缓冲区写入(glDepthMask(GL_FALSE))。如果所有透明对象都是凸面且不相交,则可以对对象进行排序而不是多边形。
  3. 对于glBlendFunc(GL_SRC_ALPHA, GL_ONE)glBlend(GL_ONE, GL_ONE)(火,“魔术”粒子系统,发光):以任何顺序渲染透明场景,禁用深度缓冲区写入(glDepthMask(GL_FALSE))。
  4. 在步骤#3之后,不要渲染任何启用深度缓冲的对象。
  5. 解决方案#2:
    使用深度剥离(google it)。特别是如果透明物体彼此相交。不适用于需要解决方案#1的颗粒系统和草。


      

    然后几乎每一帧都在CPU上手动对它们进行排序

    插入排序适用于已排序或部分排序的数据。

      

    必须有一种方法将其委托给GPU ...

    我认为您可以使用具有通道(例如,alpha)的纹理在几何着色器中生成草多边形(按正确顺序),该通道标记带草和不带草的区域。需要OpenGL 4,您可能需要对多边形执行某种更高级别的排序,然后输入到着色器以生成草补丁。

    单个灌木可以在顶点着色器中旋转(+ - 90/180/270度),以保持正确的多边形排序,如果它们在所有方向上完全对称。

    并且有合并排序算法可以很好地并行化,并且可以使用GDGPU方法或OpenCL / CUDA在GPU上执行。

    然而,使用这样的东西来渲染5片灌木丛大致相当于试图用榴弹发射器杀死蟑螂 - 这是有趣的事情,但效率不高。

    我建议忘记“将其卸载到GPU”,直到遇到性能问题为止。使用分析器并在优化之前始终进行测量,否则您将浪费大量的开发时间进行不必要的优化。

答案 2 :(得分:3)

如果您使用的是WebGL或OpenGL ES 2.0(iPhone / Android),则无法进行alpha测试。相反,你不需要绘制透明像素。这样它们就不会影响深度缓冲区,因为没有写入像素。为此,您需要丢弃片段着色器中透明的像素。你可以硬编码

...
void main() {
   vec4 color = texture2D(u_someSampler, v_someUVs);
   if (color.a == 0.0) {
     discard;
   }
   gl_FragColor = color;
}

或者您可以模拟旧式alpha测试,您可以在其中设置Alpha值

...
uniform float u_alphaTest;
void main() {
   vec4 color = texture2D(u_someSampler, v_someUVs);
   if (color.a < u_alphaTest) {
     discard;
   }
   gl_FragColor = color;
}