glScissor()调用另一个glScissor()

时间:2013-02-01 11:25:39

标签: c++ user-interface opengl

我在我的应用程序中使用glScissor()并且它正常工作,但我遇到了一个问题: 我有Window对象,其中绘图区域由glScissor()指定,在此区域内,我正在绘制我的ListView对象,其中也应使用{指定绘图区域{1}}因为我不想全部画出来。

在代码中,我可以将其表示为:

glScissor()

但当然在这种情况下启用/禁用调用是错误的:

Window::draw() 
{
   glEnable(GL_SCISSOR_TEST);
    glScissor(x, y, width, height);
        // Draw some components...
        mListView.draw(); // mListView is an object of ListView type
   glDisable(GL_SCISSOR_TEST);
}

ListView::draw()
{
  glEnable(GL_SCISSOR_TEST);
    glScissor(x, y, width, height);
        // Draw a chosen part of ListView here
   glDisable(GL_SCISSOR_TEST);
}

如果我删除那些内部glEnable / glDisable调用(ListView中的调用),我最终会得到两个glScissor()调用,这似乎也是错误的。

修改

我想以某种方式实现两种剪刀效果,我的意思是 - 窗口应该只在它的剪切区域和内部ListView中绘制,也只在它的剪切区域中。

正如你在图片中看到的那样,我用红色矩形标记glEnable(GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST); 的剪刀区域,并且用蓝色矩形标记了我想要绘制{{{1}的区域。 1}}。这就是我试图使用嵌套剪刀的原因,但我知道它没用。基本上我的问题是,实现这一目标的最佳方法是什么?

enter image description here

3 个答案:

答案 0 :(得分:7)

由于OpenGL是一个状态机,而scissor rect与任何其他状态一样,在下次调用glScissor时会被覆盖,因此在绘制列表视图后必须正确恢复窗口的剪刀矩形。这可以通过让窗口管理它来完成:

Window::draw() 
{
    // draw some components with their own scissors
    mListView.draw(); // mListView is an object of ListView type

    glScissor(x, y, width, height);
    glEnable(GL_SCISSOR_TEST);
        // draw other stuff using window's scissor
    glDisable(GL_SCISSOR_TEST);
}

但让各个组件自己恢复剪刀状态可能更灵活,特别是如果以这种分层方式使用。为此,您可以使用已弃用的glPush/PopAttrib函数来保存和恢复scissor rect:

ListView::draw()
{
    glPushAttrib(GL_SCISSOR_BIT);
    glEnable(GL_SCISSOR_TEST);
    glScissor(x, y, width, height);
        // Draw a chosen part of ListView here
    glDisable(GL_SCISSOR_TEST);
    glPopAttrib();
}

或者您自己保存并恢复剪刀状态:

ListView::draw()
{
    // save
    int rect[4];
    bool on = glIsEnabled(GL_SCISSOR_TEST);
    glGetIntegerv(GL_SCISSOR_BOX, rect);

    glEnable(GL_SCISSOR_TEST);
    glScissor(x, y, width, height);
        // Draw a chosen part of ListView here

    // restore
    glScissor(rect[0], rect[1], rect[2], rect[3]);
    if(!on)
        glDisable(GL_SCISSOR_TEST);
}

这当然可以通过一个漂亮的RAII包装器自动化,但是你可以免费进行练习。

答案 1 :(得分:3)

已修改:一般情况。

每次使用glScissor设置剪刀状态时,都会设置剪刀状态。它没有嵌套,也没有堆叠,所以你不能使用glScissor的嵌套调用来“子扫描”。您必须手动计算ListViewWindow边界值的矩形交点,然后在绘制ListView时剪切到该值。

在一般情况下,您将手动维护一堆剪刀矩形。在绘制每个子元素时,将子元素的边界矩形与堆栈的当前顶部相交,并将其用作该子元素的剪刀。在绘制子项时将新子矩阵推入堆栈,并在返回层次结构时弹出它。

如果您正在将其他内容绘制到Window,您还必须确保正确处理透支;通过设置Z排序和启用深度缓冲,或通过禁用深度缓冲和从前到后绘制内容。剪刀不会帮助您屏蔽Window背后的ListView内容,因为剪刀只能是矩形区域。

答案 2 :(得分:1)

OpenGL是一个状态机。您可以根据需要随时调用glScissor,glEnable和glDisable。它们不像必须匹配的开合式支架。如果你的电话“弃牌”,那就没问题了。只是不要指望一个剪刀与另一个剪刀合并;它只会改变/覆盖以前的设置。