OpenGL中不需要的三角形--- Z-fighting?

时间:2017-02-11 11:01:41

标签: java opengl graphics lwjgl

我目前正在编写一个使用LWJGL生成低聚场景的小程序。我先是翻了个房子。然后我渲染了地形。最后,我渲染了水。水最初是顶点的平面。我使用Perlin噪声算法在顶点着色器中进行了一些位移以产生一些波(即,我无法获得特定点的实际水位)。当我渲染场景时,我观察到一些锯齿状边缘。

从更远的距离观看时情况更糟。 enter image description here

他们是什么?我该如何删除它们?抱歉,我无法上传代码。因为行数过大。

编辑1:

private float FOV = 70;
private float NEAR_PLANE = .1f;
private float FAR_PLANE = 1000f;

private void createProjectionMatrix() {

    float aspectRatio = (float) Display.getWidth() / (float) Display.getHeight();
    float y_scale = (float) ( (1f/ Math.tan(FOV/2f))*aspectRatio );
    float x_scale = y_scale / aspectRatio;
    float frustum_length = FAR_PLANE - NEAR_PLANE;

    projectionMatrix = new Matrix4f();
    projectionMatrix.m00 = x_scale;
    projectionMatrix.m11 = y_scale;
    projectionMatrix.m22 = -((FAR_PLANE + NEAR_PLANE) / frustum_length);
    projectionMatrix.m23 = -1;
    projectionMatrix.m32 = -((2*NEAR_PLANE * FAR_PLANE) / frustum_length);
    projectionMatrix.m33 = 0;

}

2 个答案:

答案 0 :(得分:3)

问题是由于Z-buffer存储的片段Z值具有低精度。看看你的价值观:

private float NEAR_PLANE = .1f;
private float FAR_PLANE = 1000f;

所以可见深度范围是z = < 0.1 , 1000.0 >,这被标准化为< 0.0 , 1.0>范围。现在,如果 pixelformat 仅使用16位Z缓冲区(假设线性Z缓冲区不是这种情况),则精度为~(1000.0/0.1)/2^16 = 0.6,这是最小的Z步长。现在,如果考虑到Z缓冲区值非线性映射,那么距离Z_Near越远,精度就越低。

要改善这一点,您可以:

    如果gfx支持
  1. 将像素格式更改为32bits深度缓冲区
  2. 较低Zfar/Znear比率

    Znear更重要(由于非线性Z值)。越接近零,这就越糟糕。如果要渲染分辨率为米的对象,则没有必要使用z_near < 1.0

  3. 累积更多的frustrums

    如果您需要覆盖非常高的动态范围,您可以在一次通过中渲染场景。有关详细信息,请参阅

    特别是子弹#1

  4. 使用线性Z缓冲区

    这可以通过着色器摆脱非线性来实现。

答案 1 :(得分:2)

你正在进行z战斗。这意味着两个重叠三角形之间的z差异非常接近,计算机只有很多精度。因此,您正在失去足够的深度精度来正确渲染场景。

原因是你的投影接近z非常接近。将它移动到1.0f会很有帮助。当然,如果你将你的far-z移到10,000,你会遇到类似的问题(虽然不是很糟糕)。

如果您可以访问OpenGL 4.5或ARB_clip_control,则可以极大地改善情况,而无需更改投影near / far值。但这需要做三件事:

  1. 渲染到浮点深度缓冲区。这通常需要rendering to an FBO(我不知道如何使用浮点深度格式创建default framebufferdepth attachment formatGL_DEPTH_COMPONENT32F或类似。

  2. 反转近/远值。由于浮点值具有朝向零的更高精度,并且深度函数已经将精度偏向近似值,通过反转近/远范围,您将浮点精度应用于远值而不是已经精确的近值

  3. 将剪辑空间设置为使用[0,1] Z范围:

    glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
    

    如果你想要了解它的全部细节,以及所有的数学go here。总而言之,您将OpenGL的NDC空间Z范围从[-1,1]更改为[0,1]。这会影响剪裁和窗口坐标变换。通过这样做,您可以避免窗口坐标转换对值执行+ 0.5f,否则会破坏您的浮点指数。这使得上一步实际上有所帮助;没有这个,上一步就不会有任何结果。

    当然,您还需要更改构建透视投影矩阵的方式,因为它被设计为转到[-1,1]范围:

    projectionMatrix = new Matrix4f();
    projectionMatrix.m00 = x_scale;
    projectionMatrix.m11 = y_scale;
    projectionMatrix.m22 = -(NEAR_PLANE / frustum_length);
    projectionMatrix.m23 = -1;
    projectionMatrix.m32 = -((NEAR_PLANE * FAR_PLANE) / frustum_length);
    projectionMatrix.m33 = 0;
    

    另外,请记住,您需要反转传入此函数的近和远z值。

相关问题