如何实现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();
两个视口相机都跟随角色,一个是第三人称视角,另一个是自上而下。可能更难看,但迷你地图视口的背景干扰了大型背景(大型背景几乎作为迷你地图的背景)。有时大视口会覆盖小视口。
答案 0 :(得分:10)
视口不是迷你窗口。视口只不过是主窗口中进行渲染的位置。所有渲染仍然发生在同一帧缓冲区中。出现此问题是因为两个视口都使用相同的深度缓冲区。 OpenGL不知道您希望较大场景中的深度影响较小场景中的渲染。这只是一个场景,一个帧缓冲,对OpenGL来说。
有许多方法可以解决这个问题,所有这些方法都有不同的性能影响/ OpenGL要求:
使用glClear(GL_DEPTH_BUFFER_BIT);
清除两个场景之间的深度缓冲区。这是最简单的,但在性能方面成本最高。我只是为了完整起见而在此列出;你应该改为使用:
先画出你的大场景。然后将视口设置为较小的场景。关闭深度测试,但保持glDepthMask
开启。然后绘制一个屏幕对齐的四边形,其Z为-1,其中四边形的范围在X和Y中为[-1,1]。矩阵应该是投影和模型视图矩阵的标识。这将有效地清除部分场景的深度。
在绘制四边形后,不要忘记打开深度测试。如果需要,也不要忘记修复你的矩阵。这仅在您绘制到新视口的每个像素时才有效(除非您将四边形的颜色设置为预期的背景颜色)。
先画出你的大场景。然后使用glScissor
to set the scissor box到较小的场景,并使用glEnable(GL_SCISSOR_TEST)
启用剪裁。之后,使用glClear(GL_DEPTH_BUFFER_BIT)
清除深度缓冲区。然后禁用剪刀测试并渲染较小的场景。
这就像#2,除了你不必画一个屏幕对齐的四边形。当剪刀测试启用时,glClear
尊重剪刀盒,因此它只会清除剪切区域。
我提供此替代而不是建议的机制,因为OpenGL实现可能会导致glClear
和glScissor
行为错误。这应该是首选机制。
雇用the depth range。这可能会影响场景的质量,但它可能是最快的(注意:除非你有真正的理由,否则你不应该关心。也就是说,只有在分析表明性能有问题时才这样做)。对于您的主场景,请使用glDepthRange(0.1, 1.0)
;对于您的小场景,请使用glDepthRange(0.0, 0.1)
。
这实际上意味着小场景的所有深度值都将位于大场景的所有深度值的前面。但是,这也意味着您的大型场景的深度精度会降低,因此z-fighting可能很明显。
您可以根据需要移动0.1
;你可以将范围分成0.5,但我个人建议不要这样做。小场景不太重要,在较小的分辨率下,z-fighting不太重要。因此,您应该为最重要的场景提供更高的精确度。
渲染小场景to an FBO and blit it to the screen。这是最简单的推理。只需创建一些渲染缓冲区,一个用于颜色,一个用于深度。将它们粘贴在帧缓冲对象中。在那里渲染你的小场景。然后使用glBlitFramebuffer
将其绘制到默认帧缓冲区中所需的位置。
还有其他方法,比如使用模板测试,但这些是你可以依赖的方法。