OpenGL - Java - 渲染问题,多边形闪烁和消失

时间:2014-08-30 08:12:24

标签: java opengl rendering glsl lwjgl

我在使用LWJGL和GLSL着色器在Java中渲染Master Cheif时遇到了一些麻烦,其中有一些闪烁,消失的多边形和奇怪的颜色。而对于我的生活,我无法弄清楚为什么。

它应该是什么样的: enter image description here

当我稍微移动相机时它看起来像什么: enter image description here

着色器: https://github.com/marko5049/LucidEngine/tree/master/src/res/shaders

MainShaders: LightingMain ShdaowMapping Smapler 过滤

所有代码: https://github.com/marko5049/LucidEngine

静态网格:

public void addVertices(Vertex[] vertices, int[] indices, boolean calcNorm) {
    if(calcNorm) {
        vertices = calcNormals(vertices, indices);
    }

    handler.setSize(indices.length);
    EngineCore.polycount += indices.length/3;

    glBindBuffer(GL_ARRAY_BUFFER, handler.getVbo());
    glBufferData(GL_ARRAY_BUFFER, Util.createFlippedBuffer(vertices), GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handler.getIbo());
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, Util.createFlippedBuffer(indices), GL_STATIC_DRAW);
}

private void finalDraw(int typeIndex) {
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glEnableVertexAttribArray(2);
    glEnableVertexAttribArray(3);

    glBindBuffer(GL_ARRAY_BUFFER, handler.getVbo());
    glVertexAttribPointer(0, 3, GL_FLOAT, false, Vertex.SIZE * 4, 0);
    glVertexAttribPointer(1, 2, GL_FLOAT, false, Vertex.SIZE * 4, 12);
    glVertexAttribPointer(2, 3, GL_FLOAT, false, Vertex.SIZE * 4, 20);
    glVertexAttribPointer(3, 3, GL_FLOAT, false, Vertex.SIZE * 4, 32);
    glVertexAttribPointer(3, 3, GL_FLOAT, false, Vertex.SIZE * 4, 44);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handler.getIbo());
    glDrawElements(typeIndex, handler.getSize(), GL_UNSIGNED_INT, 0);

    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
    glDisableVertexAttribArray(2);
    glDisableVertexAttribArray(3);
}

1 个答案:

答案 0 :(得分:2)

您描述并在示例图像中显示的是典型的问题症状,通常称为“深度战斗”#34;或" z-fighting"。这是由深度缓冲区的精度限制引起的。

最常见的情况是,如果深度缓冲区覆盖的范围很大,并且场景包含深度值非常相似的多边形,则会出现问题。

例如,在世界空间中对多边形B前面的多边形A进行描绘。在应用所有变换之后,来自多边形A和多边形B的像素可以以相同的深度值结束,并且将得到的深度四舍五入到可用的深度缓冲精度。根据绘图的顺序,在这种情况下,多边形A或多边形B的像素将是可见的。典型的结果是多边形A和多边形B的像素混合将显示多边形A应覆盖多边形B的位置。

有很多方法可以解决这个问题:

  • 缩小深度范围。在标准透视投影中,这由近和远平面距离控制,其中相对远/近值是临界量。哪个值导致深度战斗在很大程度上取决于场景和深度缓冲精度。最安全的选择是保持相对值尽可能小。在大多数情况下,高达约100的值往往很少会导致问题,1000或更高的值可能会引发问题。
  • 增加深度缓冲精度。最常见的深度缓冲区大小为16位和24位,许多GPU都支持这两种。如果出现问题,请选择至少24位。根据硬件和OpenGL版本的不同,可能会提供更高分辨率的深度缓冲区。
  • 避免渲染深度几乎相同的多边形。删除与可见多边形非常接近的隐藏多边形,或至少将它们移动得更远。

如果上述方法不够,解决方案会变得更加复杂。在某些情况下,确实存在具有大范围深度的几何体,必须同时可见。处理这些(相对罕见的)情况的方法包括对数深度缓冲和多遍渲染方法。

请注意,我的答案纯粹是关于世界空间中的原始多边形具有不同深度的情况。如果绘制具有完全相同深度的多边形(即共面多边形),则深度对抗几乎总是结果,并且需要使用其他方法避免这种情况。由于这看起来不像这里的情景,我故意不介绍它。