OpenGL - 关于glDepthMask使用的问题

时间:2010-08-02 13:39:47

标签: opengl

我在场景中渲染了一个objectA,如下所示。场景也有许多其他对象。

void Draw()
{    
    if( glIsList( displayListID ) )
    {
        glPushAttrib( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_ENABLE_BIT );

        glEnable( GL_BLEND );
        glEnable( GL_DEPTH_TEST );
        //glDepthMask( GL_FALSE );
        glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

        glEnable( GL_LINE_SMOOTH );
        glEnable( GL_POINT_SMOOTH );
        glEnable( GL_POLYGON_SMOOTH );

        glMatrixMode( GL_MODELVIEW ); 

        color.setAlpha(alpha); // set alpha transparent of this objectA
        glCallList( displayListID );

        //glDepthMask( GL_TRUE );
        glDisable( GL_BLEND );  

        glPopAttrib();
    }
}

现在问题就在于此,

如图所示,我评论了两行 // glDepthMask(GL_FALSE); // glDepthMask(GL_TRUE);

场景正确地渲染objectA和其他对象。然而, objectA alpha的修改不再起作用(即color.setAlpha(alpha))。

如果我取消注释上面两行,那么alpha修改就会恢复正常。但是,深度渲染不正确。换句话说,有时,objectA应该在其他对象后面,但看起来objectA在所有对象的前面。

如何解决此问题?

谢谢

3 个答案:

答案 0 :(得分:62)

  1. 启用 深度掩码glDepthMask( GL_TRUE )
  2. 以任意顺序绘制所有不透明对象
  3. 关闭深度遮罩glDepthMask( GL_FALSE )
  4. 开启BLEND_MODE
  5. 绘制从最远最近
  6. 的半透明对象

    你为什么这样做?

    您需要担心2个缓冲区:深度缓冲区颜色缓冲区。这些缓冲区实际上只是大的2d数组,每个数组都是屏幕的宽度x高度。

    颜色缓冲区自然会保留每个像素的最终颜色。每个屏幕像素的颜色缓冲区中有一个条目。 深度缓冲区,就像颜色缓冲区一样,每个屏幕像素有一个条目,但它用于不同的东西。 深度缓冲区中的条目衡量每个彩色像素的“接近程度”。

    如果渲染1个距离相机很远的三角形,它会为“想要”覆盖在屏幕上的每个像素生成一组颜色和深度值。然后说你渲染另一个更接近的多边形,它还会为深度和颜色缓冲区生成一组值。现在,在像素着色时存在一种“竞争”,其中“更远的”片段(大的深度缓冲器值)被丢弃,并且仅保留最接近的片段。最接近的片段最终会为您拥有的像素着色。 (当两个多边形几乎重叠时,Z-fighting can occur

    首先使用深度蒙版渲染场景中的对象。这意味着您呈现的每个形状,当其像素变为彩色时,深度缓冲区将通过比赛的“赢家”进行更新。

    然后,你3)glDepthMask( GL_FALSE )转动关闭深度缓冲区进行书写,4)打开混合,5)渲染半透明形状从最远到最近。看起来很奇怪,是吗?

    当您关闭深度蒙版并渲染半透明形状时,OpenGL仍然会读取深度缓冲区以确定要丢弃的片段(即,如果您的半透明形状位于已渲染的实体后面)形状,然后你扔掉半透明的形状的碎片)。但它不会写入深度缓冲区,所以如果半透明的形状真的非常接近 eye (比如半透明的挡风玻璃),那些挡风玻璃碎片不要阻止实际上远离被绘制的其他碎片。这一点非常重要,因为如果你的挡风玻璃正好位于你面前并且你将它渲染成半透明,你让挡风玻璃碎片更新深度缓冲区,那么除了挡风玻璃之外你不会在场景中看到任何其他东西。即使它背后有形状,因为OpenGL会认为“嘿,由于这些深度缓冲读数,挡风玻璃是用户应该看到的唯一东西,所以我不会费心去除这个挡风玻璃以外的任何东西。”关闭深度掩码是一种“欺骗”OpenGL“不知道”的方式,有非常接近但半透明的碎片。

答案 1 :(得分:3)

一种可能的解决方案:始终将glDepthMask设置为GL_TRUE并首先绘制所有非透明对象(以任何顺序,就像您现在所做的那样),然后绘制所有(半)透明物体从后到前排序。

在某些情况下,如果您不关心绘制(半)透明对象的顺序,并且您只希望其他不透明对象“透过”,则可以跳过排序(半) )透明物体。

答案 2 :(得分:0)

如果从后到前对半透明的对象进行排序,则不必翻转深度缓冲区。
我渲染这样的半透明对象:

  1. 以任何顺序绘制所有不透明的对象。
  2. 打开混合。
  3. 绘制从后到前排序的半透明对象。

丢弃多边形时,会出现丢弃bobobobo提到的片段的问题。但是在这种情况下,禁用深度缓冲区在所有情况下都不会产生正确的结果。乍一看可能看起来不错,但是如果仔细看,您会发现混合顺序不正确:

Wrong blending

这种情况在数学上没有解决方案,因为一个多边形必须先于另一个多边形栅格化。 要解决此问题,您(或美术师)必须在3D编辑器(例如Blender)中的交点处分割多边形。因此,您可以将相交的对象分割为2个或更多,并通过排序算法对其进行适当排序。 比半透明的部分将以正确的顺序呈现:

Correct blending

请注意,第二个屏幕截图中已启用深度缓冲区写入!

如果禁用深度缓冲区,您自然会得到相同的结果,但不需要它。 实际上,如果未禁用深度缓冲区写入,则更容易看到此类重叠问题。这就是我不想禁用它的原因。