5

我正在写一个太空探索应用程序。我决定以光年为单位,并准确地模拟了恒星之间的距离。经过修补和大量艰苦的工作(主要是学习绳索),我已经让相机从穿越宇宙的星际飞船的角度正常工作。

最初我没有注意 gluPerspective () 的 zNear 参数,直到我研究行星物体。由于我的比例尺是光年单位,我很快意识到由于 zNear 为 1.0f,我将无法看到这样的物体。经过实验,我得出了这些数字:

#define POV 45
#define zNear 0.0000001f
#define zFar 100000000.0f
gluPerspective (POV, WinWidth/WinHeight, zNear ,zFar);

这非常有效,因为我能够巡航我的太阳系(位置 0,0,0)并靠近行星,这些行星看起来光线充足且纹理贴图。然而,其他系统(不在位置 0,0,0)更难通过,因为物体以不寻常的方式远离相机。

然而,我注意到在宇宙中巡航时开始出现奇怪的视觉故障。我身后的物体会“环绕”并显示在前方,如果我在 Y 方向旋转 180 度,它们也会出现在原来的位置。因此,当在太空中翘曲时,大多数恒星都正确地视差,但有些则出现并朝相反的方向行进(至少可以说令人不安)。

通过将 zNear 更改为 0.1f 可以立即纠正所有这些故障(但也不会解决太阳系物体)。所以我被困住了。我也尝试过使用 glFrustum 并产生完全相同的结果。

我使用以下内容来查看世界:

glTranslatef(pos_x, pos_y, pos_z);

根据需要使用相关的相机代码进行定位。即使禁用相机功能也不会改变任何东西。我什至尝试过 gluLookAt() 并再次产生相同的结果。

使用极端 zNear / zFar 值时 gluPerspective() 是否有限制?我试图缩小范围,但无济于事。我什至通过放大所有内容并使用更大的 zNear 值将我的世界单位从光年更改为公里 - 没有。帮助!

4

3 回答 3

5

问题是你想同时解决太多问题。你想在太阳系的尺度上观察事物,同时也有半银河的尺度。那根本不可能。不使用实时渲染器。

只有这么多的浮点精度可以解决。随着您的 zNear非常接近,您基本上已经破坏了距离相机超过 0.0001 的任何深度缓冲区。

您需要做的是根据距离绘制事物。近处物体(在太阳系范围内)使用一个透视矩阵绘制,使用一个深度范围(例如,0 到 0.8)。然后使用不同的透视矩阵和不同的深度范围(0.8 到 1)绘制更远的对象。这确实是您完成这项工作的唯一方法。

此外,您可能需要以双精度数学计算 CPU 上对象的矩阵,然后将它们转换回单精度以供 OpenGL 使用。

于 2011-09-07T18:35:20.020 回答
3

OpenGL 不应该比 zFar 更远,或者比 zNear 更靠近相机。

但是对于介于两者之间的事情,OpenGL 会计算一个深度值,该值存储在深度缓冲区中,用于判断一个对象是否阻塞了另一个对象。不幸的是,深度缓冲区的精度有限(通常为 16 或 24 位),据此大约 log2(zFar/zNear) 位的精度会丢失。因此,10^15(约 50 位丢失)的 zFar/zNear 比率必然会导致问题。一种选择是稍微增加 zNear(如果可以的话)。否则,您将需要查看拆分深度缓冲区或对数深度缓冲区

于 2011-09-11T03:13:46.360 回答
1

尼可波拉斯已经告诉过你一个故事。另一个是,您应该开始考虑存储坐标的结构化方法:存储每个对象相对于重力支配它的对象的位置,并为这些对象使用适当的单位。

所以你有星星。恒星之间的距离以光年为单位。恒星是由行星绕行的。恒星系统内的距离以光分钟到光小​​时为单位。行星是由卫星环绕的。行星系统中的距离以光秒为单位。

要显示这样的比例,您需要多次渲染。带有鳞片的物体形成一棵树。首先,将远处的分支排序为关闭,然后首先遍历树的深度。对于每个分支级别,您使用适当的投影参数,以便近→远剪辑平面紧贴要渲染的对象。渲染每个级别后清除深度缓冲区。

于 2011-09-07T21:28:22.383 回答