7

glScissor()在我的应用程序中使用它并且它工作正常,但我遇到了一个问题:我有我的Window对象,其绘图区域由该区域指定glScissor()并在该区域内,我正在绘制我的ListView对象,其绘图区域也应指定为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(GL_SCISSOR_TEST);
   glEnable(GL_SCISSOR_TEST);
   glDisable(GL_SCISSOR_TEST);
glDisable(GL_SCISSOR_TEST);

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

编辑

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

正如您在图片中看到的,我用红色矩形标记了WindowWORKS 的剪刀区域,用蓝色矩形标记了我想在其上绘制ListView. 这就是我尝试使用嵌套剪刀的原因,但我知道它没用。所以基本上我的问题是,实现这一目标的最佳方法是什么?

在此处输入图像描述

4

3 回答 3

8

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

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函数来保存和恢复剪刀矩形:

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 包装器实现自动化,但您可以免费练习。

于 2013-02-01T12:14:51.517 回答
4

编辑:一般情况。

每次使用 设置剪刀状态时glScissor,都会设置剪刀状态。它不嵌套,也不堆叠,因此您不能通过对glScissor. 您必须手动计算ListView您的边界矩形和Window边界矩形的矩形交集,然后在绘图时对其进行剪裁ListView

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

如果您将其他内容绘制到Window,您还必须确保正确处理过度绘制;通过设置 Z 排序并启用深度缓冲,或者通过禁用深度缓冲并从后到前绘制内容。Scissoring 不会帮助您掩盖Window后面的内容ListView,因为 scissors 只能是矩形区域。

于 2013-02-01T11:33:46.133 回答
1

OpenGL是一个状态机。您可以根据需要随时调用 glScissor、glEnable 和 glDisable。它们不像必须匹配的开闭大括号。如果你的电话像这样“折叠”,那没问题。只是不要指望一把剪刀会与另一把剪刀合并;它只会更改/覆盖以前的设置。

于 2013-02-01T11:30:52.507 回答