1

如何实现 2 个视口之间的清晰分离?

我有 2 个视口,一个需要全屏长度,另一个需要小于或等于屏幕尺寸的四分之一(我希望它是地图)。问题是他们一直在干扰,我从大视口中看到了小视口的内容。

这是display()我正在使用的功能:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glEnable(GL_LIGHTING);


glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0,0,newWidth,newHeight);
gluPerspective(45,(float)newWidth/(float)newHeight,0.2,500);
//setup view
glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

camera.render(crntMode, radiusNew);

//ground
glColor3f(0.5,0.5,0.5);
draw_ground(50,50,2,2,-2);
...
...
...
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(newWidth / 2, newHeight / 2, newWidth / 2, newHeight / 2);
gluPerspective(45,(float)newWidth/(float)newHeight,0.2,500);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

camera.render(mini_map, radiusNew);

//ground
glColor3f(0.5,0.5,0.5);
draw_ground(50,50,2,2,-2);
...
...
...
//swap buffers
glutSwapBuffers();

两个视口摄像机都在跟随角色,一个是第三人称视角,另一个是自顶向上。 可能更难看到,但小地图视口的背景干扰了大视口(大视口几乎充当了小地图的背景)。 有时大视口会覆盖小视口。

两个视口摄像机都在跟随角色,一个是第三人称视角,另一个是自顶向上。可能更难看到,但小地图视口的背景干扰了大视口(大视口几乎充当了小地图的背景)。有时大视口会覆盖小视口。

4

1 回答 1

10

视口不是迷你窗口。视口只不过是主窗口中进行渲染的位置。所有渲染仍然发生在同一个帧缓冲区中。出现问题是因为两个视口都使用相同的深度缓冲区。OpenGL 不知道您希望较大场景中的深度影响较小场景中的渲染。对于 OpenGL,这只是一个场景、一个帧缓冲区。

有很多方法可以纠正这个问题,所有方法都有不同的性能影响/OpenGL 要求:

  1. 清除渲染两个场景之间的深度缓冲区glClear(GL_DEPTH_BUFFER_BIT);。这是最简单的,但在性能方面成本最高。为了完整起见,我仅在此处列出;你应该改用:

  2. 先画出你的大场景。然后将视口设置为较小的场景。关闭深度测试,但保持glDepthMask开启。然后绘制一个屏幕对齐的四边形,其 Z 为 -1,其中四边形的范围在 X 和 Y 中为 [-1, 1]。对于投影矩阵和模型视图矩阵,矩阵应该是恒等的。这将有效地清除场景一部分的深度。

    绘制四边形后不要忘记打开深度测试。如果需要,也不要忘记修复您的矩阵。这仅在您绘制到新视口的每个像素时才有效(除非您将四边形的颜色设置为预期的背景颜色)。

  3. 先画出你的大场景。然后使用glScissor将剪刀框设置为较小的场景,并使用glEnable(GL_SCISSOR_TEST)启用剪刀。之后,使用 清除深度缓冲区glClear(GL_DEPTH_BUFFER_BIT)。然后禁用剪刀测试并渲染较小的场景。

    这就像#2,除了你不必绘制一个屏幕对齐的四边形。glClear启用剪刀测试时尊重剪刀框,因此它只会清除剪刀区域。

    我将其作为替代方案而不是建议的机制提供,因为 OpenGL 实现可能会导致glClear行为glScissor错误。这应该是首选机制。

  4. 使用深度范围。这可能会影响您的场景质量,但它可能是最快的(注意:除非您有真正的理由关心,否则您不应该关心。也就是说,只有在分析表明性能存在问题时才这样做)。对于您的主要场景,请使用glDepthRange(0.1, 1.0); 对于您的小场景,请使用glDepthRange(0.0, 0.1).

    这实际上意味着小场景的所有深度值都将在大场景的所有深度值之前。但是,这也意味着您的大场景的深度精度会降低,因此 z-fighting 可能很明显。

    您可以随意移动0.1;您可以用 0.5 将范围分成两半,但我个人建议不要这样做。小场景不太重要,z-fighting 在较小的分辨率下不太重要。所以你应该对最重要的场景给予更高的精度。

  5. 将小场景渲染到 FBO 并将其 blit 到屏幕上。这是最简单的推理。只需创建一些渲染缓冲区,一个用于颜色,一个用于深度。将它们粘贴在帧缓冲区对象中。在那里渲染你的小场景。然后使用glBlitFramebuffer将其绘制到默认帧缓冲区中您想要的位置。

还有其他方法,例如使用模板测试,但这些是您可以依赖的方法。

于 2012-12-04T20:30:09.677 回答