这个简单的 OpenGL/JOGL 模板测试有啥问题?

Posted

技术标签:

【中文标题】这个简单的 OpenGL/JOGL 模板测试有啥问题?【英文标题】:What's wrong with this simple OpenGL/JOGL stencil test?这个简单的 OpenGL/JOGL 模板测试有什么问题? 【发布时间】:2013-09-26 20:25:09 【问题描述】:

我正在学习如何使用模板缓冲区,但到目前为止,即使是一个简单的示例也未能成功。事实上,尽管尝试了 glStencilOpglStencilFunc 的各种参数组合,但我还没有看到任何证据表明模板缓冲区正在工作。我开始怀疑我的图形驱动程序(Mac Pro、Mac OS X 10.8.5)或 JOGL (2.0.2) 不支持它......或者我错过了一些非常基本的东西。

这是我所看到的:

我期待看到红色钻石被绿色钻石剪掉。我做错了什么?

public class Test 

    public static void main(String[] args) 
        GLProfile glprofile = GLProfile.getDefault();
        final GLCapabilities glcapabilities = new GLCapabilities(glprofile);
        final GLCanvas glcanvas = new GLCanvas(glcapabilities);
        final GLU glu = new GLU();

        glcanvas.addGLEventListener(new GLEventListener() 

            @Override
            public void reshape(GLAutoDrawable glautodrawable, int x, int y, int width, int height) 



            @Override
            public void init(GLAutoDrawable glautodrawable) 
                GL2 gl = glautodrawable.getGL().getGL2();

                glcapabilities.setStencilBits(8);

                gl.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
                gl.glLoadIdentity();

                glu.gluPerspective(45, 1, 1, 10000);
                glu.gluLookAt(0, 0, 100, 0, 0, 0, 0, 1, 0);

                gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
                gl.glLoadIdentity();
            



            @Override
            public void dispose(GLAutoDrawable glautodrawable) 



            @Override
            public void display(GLAutoDrawable glautodrawable) 
                GL2 gl = glautodrawable.getGL().getGL2();

                gl.glEnable(GL.GL_STENCIL_TEST);

                gl.glClearStencil(0x0);
                gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT | GL.GL_STENCIL_BUFFER_BIT);

                gl.glStencilFunc(GL.GL_ALWAYS, 1, 1);
                gl.glStencilOp(GL.GL_REPLACE, GL.GL_REPLACE, GL.GL_REPLACE);
            gl.glStencilMask(0xFF);
                //gl.glColorMask(false, false, false, false);
                //gl.glDepthMask(false);

                gl.glColor3f(0, 1, 0);
                gl.glBegin(GL2.GL_QUADS);
                gl.glVertex2f(-25.0f, 0.0f);
                gl.glVertex2f(0.0f, 15.0f);
                gl.glVertex2f(25.0f, 0.0f);
                gl.glVertex2f(0.0f, -15.0f);
                gl.glEnd();

            gl.glStencilMask(0);
                gl.glStencilFunc(GL2.GL_EQUAL, 1, 1);
                gl.glStencilOp(GL2.GL_KEEP, GL2.GL_KEEP, GL2.GL_KEEP);
                //gl.glColorMask(true, true, true, true);
                //gl.glDepthMask(true);

                gl.glColor3f(1, 0, 0);
                gl.glBegin(GL2.GL_QUADS);
                gl.glVertex2f(-20.0f, 0.0f);
                gl.glVertex2f(0.0f, 20.0f);
                gl.glVertex2f(20.0f, 0.0f);
                gl.glVertex2f(0.0f, -20.0f);
                gl.glEnd();
            
        );

        final JFrame jframe = new JFrame("One Triangle Swing GLCanvas");
        jframe.addWindowListener(new WindowAdapter() 

            @Override
            public void windowClosing(WindowEvent windowevent) 
                jframe.dispose();
                System.exit(0);
            
        );

        jframe.getContentPane().add(glcanvas, BorderLayout.CENTER);
        jframe.setSize(640, 480);
        jframe.setVisible(true);
    

【问题讨论】:

我认为你错过了一个调用 glStencilMask() 的调用。 en.wikibooks.org/wiki/OpenGL_Programming/Stencil_buffer @zero298 我尝试了使用和不使用glStencilMask。我将它添加到上面的示例中,它仍然会产生相同的图像。 试试我的新编辑。复制并粘贴代码后,更改功能就起作用了。 【参考方案1】:

Zero298 有正确的想法,但无法解释为什么您在代码中尝试的内容不起作用。当您了解帧缓冲区像素格式在 OpenGL 中的工作原理时,这一点会变得更加明显;我将在下面稍微讨论一下,但首先只是重新散列正确的解决方案:

public static void main(String[] args) 
    GLProfile      glprofile      = GLProfile.getDefault ();
    GLCapabilities glcapabilities = new GLCapabilities   (glprofile);

    // You must do this _BEFORE_ creating a render context
    glcapabilities.setStencilBits (8);

    final GLCanvas glcanvas = new GLCanvas (glcapabilities);
    final GLU      glu      = new GLU      ();

重要的是您在创建渲染上下文(“画布”)之前执行此操作。模板缓冲区不是您可以在需要时启用或禁用的东西——您首先必须选择一种为其保留存储空间的像素格式。由于像素格式从您创建渲染上下文时就已固定,因此您需要在new GLCanvas (...) 之前执行此操作。

您实际上可以使用 FBO 在没有模板缓冲区的渲染上下文中执行模板操作,但这比您目前应该考虑的要先进得多。但是,如果您想进行 MSAA,则需要考虑一些事情,FBO 是一种在运行时更改像素格式的好方法,而不是创建和销毁渲染上下文(“画布”)。

【讨论】:

+1 感谢您指出这一点。 @zero298 的回答让我摸不着头脑,因为事实上,我的 init 方法中确实有 glcapabilities.setStencilBits(8) 啊,谢谢,我没有注意到 glCapabilities 已经在代码中了。我只是看到它不是并且知道这是一个问题。下次我一定会解释为什么会起作用。【参考方案2】:

您需要致电glStencilMask(),它可以控制写入或不写入的内容。将其设置为写或不写,绘制模板(在您的情况下为菱形),再次设置glStencilMask(),然后绘制您想要剪裁的内容。

这有一个很好的样本:Stencil Buffer explanation

编辑:

好的,我想我找到了问题所在。您需要在程序的顶部设置您的功能。

final GLCapabilities glcapabilities = new GLCapabilities(glprofile);
glcapabilities.setStencilBits(8);
final GLCanvas glcanvas = new GLCanvas(glcapabilities);

重要的部分是: glcapabilities.setStencilBits(8);

感谢:enabling stencil in jogl

【讨论】:

如果这是解决方案,我会非常高兴,但我已经尝试过了,但没有成功。请参阅我上面编辑的示例。我得到了同样的结果。 @whiskeyspider:仅仅因为您在代码中添加了该行并不意味着您做得正确。您需要创建渲染上下文之前设置功能。换句话说,在final GLCanvas glcanvas = new GLCanvas(glcapabilities);之前。

以上是关于这个简单的 OpenGL/JOGL 模板测试有啥问题?的主要内容,如果未能解决你的问题,请参考以下文章

这个简单的 C++ 模板类有啥问题?

如何在OpenGL中绘制的边界框的高度获得高度?

win系统可以连网,但是Ubuntu系统不能连。电脑装的双系统,不知道啥问

有啥好的HTML免费模板网站推荐?

虚拟机安装Ubuntu 10.04,在虚拟机启动登录后,在输入密码的地方,输不进密码,按啥键都不管用。啥问

模板测试不裁剪纹理