【问题标题】:Hiding fragments in OpenGL在 OpenGL 中隐藏片段
【发布时间】:2016-01-25 19:29:52
【问题描述】:

我正在 Android 中使用 OpenGL-ES 3.0。

为了简化我的问题,我将描述一个与我的非常相似的场景。假设我有一个以原点为中心的球体。假设我有另一个以原点为中心的球体,半径更大。最后,假设我有一个圆柱体,圆柱体顶面的中心位于原点。圆柱体与两个球体相交。场景图片如下:

这是我的初始设置:

我只想绘制两个球体之间的部分,如下所示:

但是,在我的应用程序中,两个球体中较小的一个是不可见的(尽管它存在)。它是完全透明的。因此,我想要的最终产品看起来像这样:

现在,还有一条信息:正如我之前提到的,这是对我当前场景的简化。而不是球体,我有更复杂的对象(不是简单的原始形状)。因此,从数学的角度来解决这个问题(例如仅绘制大于较小球体半径且小于较大球体半径的圆柱体部分)是行不通的。我需要从编程的角度以某种方式解决这个问题(但鉴于我对 OpenGL 的了解有限,我只能将深度测试和混合视为可行的选项)

【问题讨论】:

    标签: android opengl-es blending depth-buffer


    【解决方案1】:

    您可能可以使用模板缓冲区来做到这一点。

    我还没有编译这段代码,需要修改,但这是大体思路:

    glDisable( GL_STENCIL_TEST );
    
    <Render rest of scene (everything other than the spheres and cylinder)>
    
    // Render the larger sphere into the stencil buffer, setting stencil bits to 1
    
    glEnable( GL_STENCIL_TEST );
    glClear( GL_STENCIL_BUFFER_BIT ); 
    glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );  // Don't render into the color buffer
    glDepthMask( GL_FALSE );    // Don't render into the depth buffer
    glStencilMask( 0xff ); // Enable writing to stencil buffer
    glStencilFunc( GL_ALWAYS, 1, 0xff );    // Write 1s into stencil buffer
    glStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE ); // Overwrite for every fragment that passes depth test (and stencil <- GL_ALWAYS)
    
    <Render big sphere>
    
    // Render the smaller sphere into the stencil buffer, setting stencil bits to 0 (it carves out the big sphere)
    
    glStencilFunc( GL_ALWAYS, 0, 0xff );    // Write 0s into stencil buffer
    
    <Render small sphere>
    
    // Render the cylinder into the color buffer, only where the stencil bits are 1
    
    glStencilMask( 0 ); // Don't need to write to stencil buffer
    glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );  // Render into the color buffer
    glStencilFunc( GL_EQUAL, 1, 0xff ); // Only render where there are 1s in the stencil buffer
    
    <Render cylinder>
    
    glDisable( GL_STENCIL_TEST );
    
    // Now render the translucent big sphere using alpha blending
    
    <Render big sphere>
    

    【讨论】:

    • 我有一个问题:我认为您建议的代码有些问题。让我解释一下我对您的代码的理解,如果这是不正确的理解,请告诉我:
    • 因此,您首先要清除缓冲区并在各处写入 1。然后覆盖通过深度测试的位置并替换这些值(顺便说一下,用什么替换?)。然后你为第二个球体写 0。那么任何有 1s 的地方都会画出圆柱体,对吗?
    • 我将您的代码从 GL_REPLACE 更改为 GL_ZERO。这不是更有意义吗?如果深度测试通过(在我的情况下,如果片段通过深度测试,它将位于大球体之外),并且模板测试通过(它总是这样做),我不应该设置这些值吗0 在缓冲区?
    • 清除模板缓冲区(带0);对于通过深度测试的每个片段,大球体将 1 写入模板缓冲区:glStencilFunc( GL_ALWAYS, 1, 0xff ); - 片段始终通过模板测试,设置 ref 值 = 1,glStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE ); - 如果片段通过模板测试(和深度测试)然后用 ref 值(在本例中为 1)替换该 pos 处的现有模板位;对小球体做同样的事情,除了参考值 0(是的,你也可以做 glStencilOp( GL_KEEP, GL_KEEP, GL_ZERO );
    • 那么只有在它们的位置有模板值 1 时才将片段渲染到颜色缓冲区中:glStencilFunc( GL_EQUAL, 1, 0xff );
    【解决方案2】:

    您所描述的是Constructive Solid Geometry,但使用网格作为基本类型之一增加了复杂性。

    只有数学上简单的图元的事件,纯粹在 OpenGL 管道中实现 CSG 非常困难,因为您需要找到一种方法来以着色器可以理解和有效解析的方式表示场景图。一旦添加了网格,这基本上是不可能的,因为顶点和片段着色器无法轻松访问网格几何体。

    您可能可以通过对 CGS 图中的每个项目执行绘制调用以及巧妙地操纵模板和深度缓冲区来近似它,但您可能最终仍会遇到许多无法正确渲染的边缘情况。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-27
      • 1970-01-01
      • 2015-09-29
      • 2016-09-03
      • 2012-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多