用于绘图的OpenGL ES xor模式

时间:2013-02-27 10:12:21

标签: opengl-es

OpenGL ES是否具有XOR绘图模式?我想在该模式下绘制一个立方体,然后绘制一个与立方体相交的球体,输出应该是立方体的一部分和球体的一部分但是具有空的交点。

1 个答案:

答案 0 :(得分:3)

假设您希望投影后两个对象的图像空间交叉而不是立方体与球体的实际几何交叉(因为这绝对不是OpenGL的用途),您可以使用stencil {{ 3}}为此:

首先确保你有一个模板缓冲区(取决于你的上下文创建框架,不知道Cocos3D是如何做到的,但是OpenGL ES 1本身支持模板测试)。然后当然在执行立方体和球体之前启用模板处理,并在帧的开始处清除模板缓冲区(可能与您的其他缓冲区一起):

glClear(... | GL_STENCIL_BUFFER_BIT);
...
glEnable(GL_STENCIL_TEST);

首先,我们只将立方体渲染到模板缓冲区中,为每个绘制的像素增加模板值(从0开始)。

glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); //don't really draw anything
glStencilFunc(GL_ALWAYS, 0, -1);    //always pass the test (default anyway)
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);  //increment for each drawn pixel
//draw object

然后我们对球体做同样的事情。之后,模板缓冲区的立方体像素或球体像素到处都是1,而立方体和球体像素的所有位置都是2

然后我们只是正常地绘制两个东西,但只有在模板缓冲区不是2的情况下(或者如果你想要它在1的地方),因此我们不会在交叉点绘制任何东西:

glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);  //draw something
glStencilFunc(GL_NOTEQUAL, 2, -1);      //draw everywhere except at intersection
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);    //leave the stencil buffer as is
//draw cube
//draw sphere

最后,我们再次禁用模板测试(glDisable(GL_STENCIL_TEST))。

这只是一个基本的例子,但它应该让你开始使用功能强大的模板缓冲区。

目前,整个事物依赖于深度测试结果,这意味着它取决于您绘制对象的顺序。如果您希望它与深度无关(因此只考虑其2D屏幕投影),那么你既可以在没有深度测试的情况下绘制对象,也可以将glStencilOp的第二个参数(这是模板测试通过但深度测试失败时执行的操作)设置为GL_INCR

此刻它也只有在启用了背面剔除时才有效,因为否则每个对象的模板值会增加两次(至少如果忽略深度),非凸对象的情况会更糟糕。也许您还可以使用其他模板操作来执行任务,但遗憾的是OpenGL ES 1似乎不支持模板值的二进制操作,也没有包装操作(因此递减0再次为0)。

编辑:好的,你真的想要3D物体之间的几何交叉(或者看起来不同)。那么你的问题是OpenGL本身无法解决的。 OpenGL不做任何其他事情,然后将简单的图元(点,线和三角形)绘制到屏幕上。它既不是场景管理系统也不是几何库。你想要实现的是一个不那么简单的任务(虽然使用像立方体和球体这样的简单对象肯定会有帮助),你可能需要在网格(或buffer)上寻找一些几何库来进行布尔运算来生成适当的几何差异作为三角形网格,然后可以像往常一样使用OpenGL绘制。

另一个选项,类似于你提到的“3D模板缓冲区”的概念,将使用常规网格离散空间,从而将对象细分为小体素(3D像素,想象小盒子) )。在那些离散的有限体素集上,布尔运算非常简单。但是当然这种方法是以引入离散化错误和性能开销为代价的(在体素上运行意味着在大数据集上运行,确定CSG也不容易,但可能比O(n ^ 3)更复杂)。而且您还必须再次从体素集重新创建可渲染对象,使用一些表面提取方法再次获取网格,或者只绘制小点或框。

最后使用合适的CSG库可能是你最好的选择,无论是OpenGL与它没有任何关系。