OpenGL:如何实现“橡皮擦”工具?

时间:2008-11-15 03:11:31

标签: iphone opengl-es framebuffer

我正在开发一款iPhone游戏,其中涉及绘图/绘画机制,我在尝试创建一个可以删除已绘制内容的工具时遇到问题。

主要问题是被绘制的背景不是纯色而是静态图像或动画。我尝试在绘图中使用不同的混合选项和逻辑操作,但似乎没有任何效果。我是OpenGL的新手,所以我必须遗漏一些东西。

任何提示?

编辑:为了提供更多信息,我正在为我的画笔使用纹理,并使用glVertexPointer()和glDrawArrays()来渲染它们。例如:

glBindTexture(GL_TEXTURE_2D, circleBrush);
glVertexPointer(3, GL_FLOAT, 0, verts);
glTexCoordPointer(2, GL_FLOAT, 0, coords);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

编辑2:不幸的是,iPhone上没有模板缓冲区。 :(

编辑3:iPhone上有Framebuffer对象,这就是我走的路。我还没有完全实现它,但到目前为止它看起来像我想要它的方式。谢谢大家!

5 个答案:

答案 0 :(得分:5)

在场景上绘制全屏纹理四边形。当用户绘制画笔描边时,使用glTexSubImage2D更新纹理。

glReadPixels / glDrawPixels很慢。

使用FrameBufferObjects甚至更好,但我怀疑这个扩展是否可以在iPhone上使用(然后再次,我不确定,所以也许尝试一下)。 FBO允许您直接绘制到纹理中,就像它是另一个渲染上下文一样。

答案 1 :(得分:4)

模板缓冲区是确保接近此问题的最佳方式...您将节省时间,CPU和潜在问题..,它们可在Iphone上使用,您只需要创建一个OpenGlES 2.0表面(不是gles 1.0)或1.1)。

        //Turn off writing to the Color Buffer and Depth Buffer
        //We want to draw to the Stencil Buffer only
        glColorMask(false, false, false, false);
        glDepthMask(false);

        //Enable the Stencil Buffer
        glEnable(GL_STENCIL_TEST);

        //Set 1 into the stencil buffer
        glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
        glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);

        //CALL YOUR DRAWING METHOD HERE


        //Turn on Color Buffer and Depth Buffer
        glColorMask(true, true, true, true);
        glDepthMask(true);

        //Only write to the Stencil Buffer where 1 is set
        glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
        //Keep the content of the Stencil Buffer
        glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

        //CALL OUR DRAWING METHOD AGAIN

查看此示例: http://www.opengl.org/resources/code/samples/glut_examples/examples/stenciltst.c

这是视觉效果: http://www.opengl.org/resources/code/samples/glut_examples/examples/stenciltst.jpg

我已经在Android和iPhone上实现了相同类型的橡皮擦工具,它就像一个魅力!

祝你好运!

干杯!

答案 2 :(得分:2)

你没有提供太多信息,但我认为你将他们“画”的东西存放到一个缓冲区然后在屏幕上绘制如下:

 glWindowPos2i(X, Y);
 glDrawPixels(drawing->Width, drawing->Height, drawing->Format, 
              GL_UNSIGNED_BYTE, drawing->ImageData);

使用drawing-> ImageData作为缓冲区。你可以做的是有一个单独的背景缓冲区并首先绘制它。然后擦除工具将简单地白化绘图缓冲区(将所有值,包括alpha,一直向上)。

要使此解决方案正常工作,您必须启用混合和关闭深度测试

 glEnable(GL_BLEND);
 glDisable(GL_DEPTH_TEST);
 glWindowPos2i(X, Y);
 //background never changes
 glDrawPixels(background->Width, background->Height, background->Format, 
              GL_UNSIGNED_BYTE, background->ImageData);
 glWindowPos2i(X, Y);
 glDrawPixels(drawing->Width, drawing->Height, drawing->Format, 
              GL_UNSIGNED_BYTE, drawing->ImageData);
 glEnable(GL_DEPTH_TEST);
 glDisable(GL_BLEND);

这就是你要找的东西吗?

答案 3 :(得分:2)

您可以使用模板缓冲区进行此操作。模板缓冲区是一个特殊的缓冲区,它保存每个像素的信息,类似于深度缓冲区。与深度缓冲区不同,您可以决定在绘制时如何更改模板缓冲区以及它如何影响绘制到颜色缓冲区的决策。为此,您可以在任何绘图操作之前设置特定状态。这是你做的:

  • 在用户删除时,将“已删除”区域绘制到 模板缓冲区(使用StencilOp,见下文)。您可以使用任何GL绘图 这个功能。

  • 在每个渲染过程中,首先绘制 背景(如果你愿意,你可以 在这里使用负模板测试 只绘制了“擦除”部分 背景 - 可能会增加 性能)。

  • 然后,为所有人启用模板测试 其他绘图操作。 OpenGL的 然后只会画到 “未删除的”区域。

设置模板缓冲区应如何影响绘图(或不)的功能: glStencilFunc()

设置模板缓冲区本身受绘图影响的函数: glStencilOp()

进一步解释,还有以下论点: http://www.opengl.org/resources/code/samples/sig99/advanced99/notes/node117.html

答案 4 :(得分:0)

使用glBlendFunc(GL_ONE,GL_ZERO)模式可以很简单。