2012-12-04 112 views
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(); 

Both viewport cameras are following the character, one from a third person perspective, the other one from top up. It might be harder to see, but the background from the mini-map viewport is interfering with large one (the large on is acting almost as a background for the mini-map). Sometimes the large viewport covers the small viewport.

两个视摄像机后面的字符,一个从第三人称视角,从上了另外一个。可能很难看到,但是迷你地图视口的背景干扰了大型地图(大型地图几乎作为迷你地图的背景)。有时,大视口覆盖小视口。

+3

“*问题是他们不断干扰*”以什么方式?这究竟如何体现?你分别画什么样的东西? –

+0

添加了屏幕截图。我正在捕获同样的东西,但使用不同的相机位置。 –

+0

我想说的是,小型视口需要始终处于顶峰。就我而言,我从大视口中抽出的墙壁覆盖了较小的一个。 –

回答

10

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

有很多方法来解决这个问题,都具有不同的性能影响/ OpenGL的要求:

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

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

    不要忘了在绘制四边形之后再进行深度测试。如果需要,也别忘记修复你的矩阵。如果您正在绘制新视口的每个像素(除非您将四边形的颜色设置为预期的背景色),这将仅适用。

  3. 先画出你的大场景。然后使用glScissor to set the scissor box到较小的场景,并使用glEnable(GL_SCISSOR_TEST)来启用剪刀。之后,用glClear(GL_DEPTH_BUFFER_BIT)清除深度缓冲区。然后禁用剪刀测试并渲染较小的场景。

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

    我提供这个作为替代,而不是建议的机制,因为OpenGL实现可以使glClearglScissor行为错误。这应该是首选机制。

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

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

    如果您认为合适,您可以将0.1左右移动;你可以用0.5分割一半的范围,但我个人建议反对它。小场景不那么重要,z战斗在较小的分辨率下不那么重要。所以你应该给最重要的场景更精确。

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

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

+0

谢谢,先生!它按照预期工作! –

+1

@ Cookie503:我增加了几个选项。 –