在 OpenGL 中隐藏片段
Hiding fragments in OpenGL
我在 Android 中使用 OpenGL-ES 3.0。
为了简化我的问题,我将描述一个与我非常相似的场景。假设我有一个以原点为中心的球体。假设我有另一个以原点为中心的球体,半径更大。最后,假设我有一个圆柱体,圆柱体顶面的中心位于原点。圆柱体与两个球体相交。场景图片如下:
这是我的初始设置:
我只想画两个球体之间的部分,如下图:
但是,在我的应用程序中,两个球体中较小的一个不可见(尽管它存在)。它是完全透明的。因此,我想要的最终产品看起来像这样:
现在,再提供一条信息:正如我之前提到的,这是对我当前场景的简化。我没有球体,而是复杂得多的对象(不是简单的原始形状)。因此,从数学角度来解决这个问题(例如只绘制大于较小球体半径且小于较大球体半径的圆柱体部分)是行不通的。我需要从编程的角度来解决这个问题(但鉴于我对 OpenGL 的了解有限,我只能将深度测试和混合视为可行的选择)
您所描述的是 Constructive Solid Geometry,但使用网格作为基本类型之一会增加复杂性。
只有数学上简单的基元的事件,很难完全在 OpenGL 管道中实现 CSG,因为您需要找到一种方法来以着色器可以理解和有效解析的方式表示场景图。一旦添加网格,这基本上是不可能的,因为顶点和片段着色器将无法轻松访问网格几何体。
您可以通过对 CGS 图中的每个项目执行绘制调用并巧妙地操纵模板和深度缓冲区来近似它,但您可能仍然会遇到许多未渲染的边缘情况正确。
您或许可以使用模板缓冲区来做到这一点。
我还没有编译这段代码,它需要修改,但这是总体思路:
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>
我在 Android 中使用 OpenGL-ES 3.0。
为了简化我的问题,我将描述一个与我非常相似的场景。假设我有一个以原点为中心的球体。假设我有另一个以原点为中心的球体,半径更大。最后,假设我有一个圆柱体,圆柱体顶面的中心位于原点。圆柱体与两个球体相交。场景图片如下:
这是我的初始设置:
我只想画两个球体之间的部分,如下图:
但是,在我的应用程序中,两个球体中较小的一个不可见(尽管它存在)。它是完全透明的。因此,我想要的最终产品看起来像这样:
现在,再提供一条信息:正如我之前提到的,这是对我当前场景的简化。我没有球体,而是复杂得多的对象(不是简单的原始形状)。因此,从数学角度来解决这个问题(例如只绘制大于较小球体半径且小于较大球体半径的圆柱体部分)是行不通的。我需要从编程的角度来解决这个问题(但鉴于我对 OpenGL 的了解有限,我只能将深度测试和混合视为可行的选择)
您所描述的是 Constructive Solid Geometry,但使用网格作为基本类型之一会增加复杂性。
只有数学上简单的基元的事件,很难完全在 OpenGL 管道中实现 CSG,因为您需要找到一种方法来以着色器可以理解和有效解析的方式表示场景图。一旦添加网格,这基本上是不可能的,因为顶点和片段着色器将无法轻松访问网格几何体。
您可以通过对 CGS 图中的每个项目执行绘制调用并巧妙地操纵模板和深度缓冲区来近似它,但您可能仍然会遇到许多未渲染的边缘情况正确。
您或许可以使用模板缓冲区来做到这一点。
我还没有编译这段代码,它需要修改,但这是总体思路:
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>