我在我的应用程序中使用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}}。这就是我试图使用嵌套剪刀的原因,但我知道它没用。基本上我的问题是,实现这一目标的最佳方法是什么?
答案 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
的嵌套调用来“子扫描”。您必须手动计算ListView
和Window
边界值的矩形交点,然后在绘制ListView
时剪切到该值。
在一般情况下,您将手动维护一堆剪刀矩形。在绘制每个子元素时,将子元素的边界矩形与堆栈的当前顶部相交,并将其用作该子元素的剪刀。在绘制子项时将新子矩阵推入堆栈,并在返回层次结构时弹出它。
如果您正在将其他内容绘制到Window
,您还必须确保正确处理透支;通过设置Z排序和启用深度缓冲,或通过禁用深度缓冲和从前到后绘制内容。剪刀不会帮助您屏蔽Window
背后的ListView
内容,因为剪刀只能是矩形区域。
答案 2 :(得分:1)
OpenGL是一个状态机。您可以根据需要随时调用glScissor,glEnable和glDisable。它们不像必须匹配的开合式支架。如果你的电话“弃牌”,那就没问题了。只是不要指望一个剪刀与另一个剪刀合并;它只会改变/覆盖以前的设置。