在OpenGL中,如何让物品按照从后往前的顺序进行绘制?

14
默认情况下,对象似乎是从前往后绘制的。我正在绘制一个2D UI对象,并希望从后往前创建它。例如,我可以先创建一个白色正方形,然后再创建一个稍小的黑色正方形放在其上方,从而创建一个带有白色边框的黑色面板。这篇文章对此进行了一些讨论,并将此顺序描述为“Painter's Algorithm”,但最终他们提供的示例只是反向渲染对象以获得所需的效果。我认为可以通过一些变换(gOrtho?)实现从后往前(首先将对象放在后面,随后的对象在其之上绘制)的渲染?
我还要提到,我不想使用类似于GLUT的封装库来解决这个问题。
我还发现,在Mac上使用Cocoa NSOpenGLView时,默认行为似乎是从后往前绘制的,而在Windows中我无法获得这种行为。我使用的Windows设置代码是:
glViewport (0, 0, wd, ht);
glMatrixMode(GL_PROJECTION);           
glLoadIdentity();                      
glOrtho (0.0f, wd, ht, 0.0f, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);             
glLoadIdentity();                       
6个回答

26

下面的调用将关闭深度测试,导致对象按创建顺序绘制。这实际上会导致对象从后往前绘制。

glDepthFunc(GL_NEVER);      // Ignore depth values (Z) to cause drawing bottom to top

请确保您不要调用这个函数:

glEnable (GL_DEPTH_TEST);   // Enables Depth Testing

1
正是我所需要的。在我的情况下,一个简单的调用glDisable(GL_DEPTH_TEST);就解决了问题。:) +1 - absentmindeduk

6
针对您的问题,OpenGL没有标准方式指定深度排序。一些实现可能默认使用前向后深度排序,因为它通常更快,但这不是保证的(正如您发现的那样)。
但我真的不明白它如何在您的情况下有所帮助。如果您在白色正方形前面绘制一个黑色正方形,则只要启用了深度缓冲,黑色正方形就应该在白色正方形前面绘制,无论它们以何种顺序绘制。如果它们实际上是共面的,则两者都不会真正在另一个之前,任何深度排序算法都将是不可预测的。
您发布链接的教程只是谈到了它,因为当您使用透明度时,深度排序是相关的。但我觉得这不是您想要的。
但是,如果您确实必须这样做,那么您必须自己完成。首先将白色正方形发送到渲染管道,强制渲染,然后再发送黑色正方形。如果您这样做,并禁用深度缓冲,则正方形可以共面,您仍将保证黑色正方形在白色正方形上绘制。

谢谢Gerald。在我的二维思维中,我根本不使用Z平面,并且期望所有对象都落在相同的Z坐标上,其中顺序非常重要以确定将显示什么。我已经实现了一个内存对象列表,可以根据标志轻松地反向迭代。 - AlanKley
我相信我找到了一种设置GL世界以启用从后向前绘制的方法。请参见我下面提供的答案。我正在取消接受此答案。 - AlanKley
你的解决方案并不是你在问题中所要求的。当然,禁用深度缓冲区将按照您提供的顺序绘制它们,但这不是一个标志,除非您自己从后往前绘制它们,否则它们不会从后往前绘制。 - Gerald
1
虽然你说你生活在一个二维世界里,所有的东西都在同一个z平面上,但我猜你对前后有不同的概念。 - Gerald

2
绘制顺序很难。没有简单的解决方案。画家算法(根据物体与相机视角的距离对物体进行排序)是最直接的方法,但正如您发现的那样,它并不能解决所有情况。
我建议将画家算法和图层结合使用。您可以为程序中的特定元素构建图层。因此,您可以得到背景图层、对象图层、特效图层和GUI图层。
对每个图层的项目使用画家算法。在某些特殊图层(例如GUI图层)中,不要使用画家算法进行排序,而是按照您的调用顺序进行排序。您首先调用白色正方形,因此它会首先绘制。

不错的想法,但这需要额外的工作。正如我所提到的,在 Mac 上,如果我没有弄错的话,它似乎可以做到我想要的。NSOpenGLView 的默认设置允许进行背向排序,无需任何特殊处理。 - AlanKley

2

将你想放在前面的物品稍微向后放置,将你想放在后面的物品稍微向后放置。也就是说,实际上改变z值(假设z垂直于屏幕平面)。你不必大幅改变它们的位置,即可使它们相互之间前后绘制。如果只稍微更改z值,你不应该会注意到它们与所需位置之间有太大的偏移。你甚至可以非常花哨地根据改变的z位置计算出正确的x、y位置,以便物品出现在其应该出现的位置。


好主意。我猜没有“自动”的方法来做到这一点。 - AlanKley
1
或者,如果你真的想生活在一个二维世界中,你可以使用正交投影。然后z值(再次假设z垂直于屏幕平面)并不重要,除了确定哪些对象被遮挡! - Noah Callaway

1

你的物品将按照你调用glBegin/glEnd函数的顺序精确绘制。你可以使用z-buffer获得深度缓冲,如果你的2D对象具有不同的z值,你可以通过这种方式获得所需的效果。除非程序手动以后到前的顺序绘制或使用z-buffer来完成此操作,否则在Mac上看到你描述的行为的唯一方法是。OpenGL没有像你描述的那样自动执行任何功能。


我描述的2个正方形是在glBegin/glEnd之间绘制的。我先绘制了白色正方形,然后是黑色正方形,但我只看到了一个白色正方形。我提出这个问题的目的是模拟一个不使用z坐标的2D世界。在Mac上,我看到一个带有白色边框的黑色正方形。 - AlanKley
1
你可能开启了z缓冲,并且绘制了两个具有相同z值的正方形。我猜测取决于两个系统之间的图形硬件和舍入误差,第二个正方形可能会“穿透”另一个正方形。只需关闭z缓冲并按所需顺序绘制正方形即可。 - Jim Buck

0
如AlanKley所指出的那样,实现此操作的方法是禁用深度缓冲区。画家算法是一种2D扫描转换技术,用于在没有类似于z缓冲区的情况下以正确顺序渲染多边形。但您不会将其应用于3D多边形。您通常会对其进行变换和投影(处理与其他多边形的交点),然后按其投影z坐标对生成的2D投影多边形列表进行排序,然后按相反的z顺序绘制它们。
我总是认为,当您无法(或不想)使用z缓冲区时,画家算法是一种隐藏表面移除的替代技术。

授予,我的例子非常具体,不涉及3D世界。我正在尝试实现一个MessageBox错误报告窗格,它将始终显示为平面。 - AlanKley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接