在OpenGL-ES中与Z战斗

时间:2013-01-13 22:55:43

标签: iphone ios opengl-es 3d

我使用OpenGL ES完成了3D iPhone游戏。

这是一个很大的世界,但是我需要绘制一些微小的第一人称视角位,所以我无法减小glFrustumf()进一步采用的深度范围(zNear vs zFar)。

当表面遇到Z战时,我将它们略微分开以阻止它们闪烁。我也让相机的距离决定了我调整它们之间的距离,如果它有用又需要它。

这基本上没问题,但是有一些东西的视角受到分离的影响,并且使分离变小会导致闪烁。我喜欢把表面画得更近一些。

有没有办法增加深度缓冲精度,所以曲面可以更接近,而不会有更窄的深度范围?

如果没有,还有其他方法吗?

我仍然在应用中使用OpenGL ES 1.1,但是如果它值得的话我愿意升级。

感谢您的帮助。


以下是我创建深度缓冲区的方法......

在init方法中:

// Create default framebuffer object. The backing will be allocated for the current layer in -resizeFromLayer
glGenFramebuffersOES(1, &defaultFramebuffer);
glGenRenderbuffersOES(1, &colorRenderbuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, colorRenderbuffer);

//Added depth buffer
glGenRenderbuffersOES(1, &depthRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);

在resizeFromLayer方法中:

// Allocate color buffer backing based on the current layer size
glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
[context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:layer];
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);

//Added depth buffer
glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);

以下是我创建截头体的方法......

const GLfloat  zNear = 2.2;
const GLfloat  zFar = 30000;
const GLfloat  fieldOfView = 60.0;
GLfloat size = zNear * tanf(degreesToRadian(fieldOfView) / 2.0);

if (LANDSCAPE) { //for landscape clip & aspect ratio.
    //parameters are: left, right, bottom, top, near, far
    glFrustumf(-size/(backingWidth/backingHeight),
               size/(backingWidth/backingHeight),
               -size, size,
               zNear, zFar);
}

3 个答案:

答案 0 :(得分:0)

OpenGL ES 1.x中不支持32位深度缓冲区。

此外,似乎iOS上不支持16位深度缓冲区,因此使用GL_DEPTH_COMPONENT16_OES只是表现为24位,这就是为什么当我使用{{{I}时没有看到任何改进的原因1}}而不是!

我在尝试将深度缓冲区设置为16位后检查GL_DEPTH_COMPONENT24_OES确认了这一点:

GL_DEPTH_BITS

输出:

glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer); glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight); GLint depthBufferBits; glGetIntegerv(GL_DEPTH_BITS, &depthBufferBits ); NSLog(@"Depth buffer bits: %d", depthBufferBits );

哦,好吧,至少现在我知道了。希望这有助于其他人。

答案 1 :(得分:0)

标准答案围绕glPolygonOffset的使用。这样做是在与缓冲区中已有的偏移深度值进行比较之前为多边形深度值添加偏移量。计算偏移量允许屏幕深度和角度,因此它与您的世界大小无关,并且不会影响要绘制的像素的身份。

问题在于决定何时使用它。如果您的场景是,例如,许多离散对象没有统一的广泛数据结构(如四叉树或BSP树),那么您可能不得不使用像桶系统这样的东西来发现物体非常接近(相对到他们的距离)并向更近的地方施加一个碰撞。如果问题是单个网格的内部问题,而你没有更高级别的结构,那么显然问题就更复杂了。

另一方面,如果您的场景完全或绝对是静态的,那么像BSP树那样可以完成大部分绘图而不需要深度缓冲的结构可能是一个优势。在绝望的结束时,您可以使用深度书写渲染回到前面但没有比较然后将移动的对象作为额外的层;在实践中,这将给你大量的透支(虽然PVS解决方案会有所帮助)与前后对比现代早期深度剔除 - 特别是在像PowerVR这样的基于延迟平铺的渲染器上 - 所以这也不是一件轻松的胜利。

作为一个单独的想法,有什么方法可以简化远处几何?

答案 2 :(得分:0)

对我有用的是调整近远值。 far和near值之间的差异定义了深度缓冲区的精确程度。 以身作则。假设你有一个10000和一个接近500.这将有一个总深度:9500 使用16位DepthBuffer,您可以获得65536种深度组合。 (根据GPU和OpenGl实现,此值根据几何图形计算) 然后,每个单位的空间大约有65536/9500~ = 7个可能的深度。那么你将获得1/7~ = .14的深度精度。如果你的物体之间的距离为.14或更小,你可能会得到z战斗。 在现实生活中,这更复杂,但想法是一样的。

也许你的远远价值很长,你不需要它。增加近似值有助于在更接近相机的物体(更明显的物体)中进行z战斗。