我在使用 LWJGL 和 GLSL 着色器在 Java 中渲染 Master Cheif 时遇到了一些问题,其中存在一些闪烁、多边形消失和奇怪的颜色。我一生都无法弄清楚为什么。
它应该是什么样子:
当我稍微移动相机时,它会是什么样子:
着色器: https://github.com/marko5049/LucidEngine/tree/master/src/res/shaders
主要着色器: 灯光主 影子映射 斯马普勒 过滤器
所有代码: 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);
}
最佳答案
您所描述的以及示例图像中显示的内容是通常称为“深度战斗”或“z-fighting”的问题的典型症状。这是由深度缓冲区的精度限制引起的。
出现此问题的最常见情况是深度缓冲区覆盖的范围很大,并且场景包含深度值非常相似的多边形。
例如,绘制一个在世界空间中稍微位于多边形 B 前面的多边形 A。应用所有变换后,多边形 A 和多边形 B 的像素最终可能具有相同的深度值,并且所得深度将四舍五入到可用的深度缓冲区精度。根据绘制顺序,在这种情况下,多边形 A 或多边形 B 中的像素将可见。典型的结果是,多边形 A 和多边形 B 的像素混合将出现在多边形 A 应覆盖多边形 B 的位置。
有多种方法可以解决这个问题:
- 减小深度范围。在标准透视投影中,这是由近平面距离和远平面距离控制的,其中相对远/近值是临界量。哪些值会导致深度冲突在很大程度上取决于场景和深度缓冲区的精度。最安全的选择是保持相对值尽可能小。在大多数情况下,大约 100 以内的值很少会引起问题,而 1000 及更高的值可能会开始引起问题。
- 提高深度缓冲区精度。最常见的深度缓冲区大小是 16 位和 24 位,许多 GPU 都支持这两种类型。如果出现问题,请至少选择 24 位。根据硬件和 OpenGL 版本,可能会提供更高分辨率的深度缓冲区。
- 避免渲染深度几乎相同的多边形。要么删除深度与可见多边形非常接近的隐藏多边形,要么至少将它们移得更远。
如果以上还不够,解决方案会变得更加复杂。在某些情况下,确实存在具有大范围深度的几何图形,必须同时可见。处理这些(相对罕见)情况的方法包括对数深度缓冲区和多 channel 渲染方法。
请注意,我的回答纯粹是关于世界空间中的原始多边形具有不同深度的情况。如果绘制深度完全相同的多边形(即共面多边形),几乎总是会导致深度冲突,需要用其他方法来避免这种情况。由于这看起来不像这里的场景,所以我故意没有涵盖它。
关于java - OpenGL - Java - 渲染问题,多边形闪烁和消失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25580397/