我目前正在编写一个使用LWJGL生成低聚场景的小程序。我先是翻了个房子。然后我渲染了地形。最后,我渲染了水。水最初是顶点的平面。我使用Perlin噪声算法在顶点着色器中进行了一些位移以产生一些波(即,我无法获得特定点的实际水位)。当我渲染场景时,我观察到一些锯齿状边缘。
他们是什么?我该如何删除它们?抱歉,我无法上传代码。因为行数过大。
编辑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;
}
答案 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
越远,精度就越低。
要改善这一点,您可以:
32bits
深度缓冲区 较低Zfar/Znear
比率
Znear
更重要(由于非线性Z值)。越接近零,这就越糟糕。如果要渲染分辨率为米的对象,则没有必要使用z_near < 1.0
累积更多的frustrums
如果您需要覆盖非常高的动态范围,您可以在一次通过中渲染场景。有关详细信息,请参阅
特别是子弹#1
使用线性Z缓冲区
这可以通过着色器摆脱非线性来实现。
答案 1 :(得分:2)
你正在进行z战斗。这意味着两个重叠三角形之间的z差异非常接近,计算机只有很多精度。因此,您正在失去足够的深度精度来正确渲染场景。
原因是你的投影接近z非常接近。将它移动到1.0f会很有帮助。当然,如果你将你的far-z移到10,000,你会遇到类似的问题(虽然不是很糟糕)。
如果您可以访问OpenGL 4.5或ARB_clip_control,则可以极大地改善情况,而无需更改投影near / far值。但这需要做三件事:
渲染到浮点深度缓冲区。这通常需要rendering to an FBO(我不知道如何使用浮点深度格式创建default framebuffer。 depth attachment format为GL_DEPTH_COMPONENT32F
或类似。
反转近/远值。由于浮点值具有朝向零的更高精度,并且深度函数已经将精度偏向近似值,通过反转近/远范围,您将浮点精度应用于远值而不是已经精确的近值
将剪辑空间设置为使用[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值。