如何从 2D 屏幕鼠标单击 OpenGL 中的大型对象获得准确的 3D 深度?

How to get accurate 3D depth from 2D screen mouse click for large scale object in OpenGL?

我正在计算 2D 屏幕鼠标点击的 3D 坐标。然后我在计算出的 3D 坐标处绘制点。代码没有问题,方法没有问题,一切正常。但是有一个问题与深度有关。

如果对象大小约为 (1000, 1000, 1000),我将获得完整深度,即对象面元的精确 3D 坐标。但是当我加载大小为 (20000, 20000, 20000) 的对象时,我没有得到准确的(深度)3D 坐标。我从表面得到一些偏移。该点与表面有一些偏移。所以我的第一个问题是为什么会这样?第二个问题是如何获得超大型物体的完整深度和准确的 3D 坐标?

我用

画了一个 3D 点
glDepthFunc(GL_LEQUAL);
glDepthRange(0.0, 0.999999);

并使用

glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &wz);
if(wz > 0.0000001f && wz < 0.999999f)
{
gluUnProject()....saving 3D coordinate
}

之所以会出现这种情况,是因为深度缓冲的精度有限。例如,一个 8 位深度缓冲区只能存储 2^8=256 个不同的深度值。

影响深度精度的第二个参数集是投影中近平面和远平面的设置,因为这是必须映射到深度缓冲区中可用数据值的范围。如果使用 8 位深度缓冲区将此范围设置为 [0, 100],则实际精度为 100/256 = ~0.39,这意味着眼睛 space 中大约 0.39 个单位将具有相同的深度赋值。

现在解决您的问题:很可能您分配给深度缓冲区的位太少。如上所述,这会引入错误,因为无法存储准确的深度值。这就是为什么点靠近表面,但不完全在表面上的原因。

我已经解决了这个因深度范围而发生的问题。因为 OpenGL 是一个状态机,所以我想我可能在某个地方改变了应该从 0.0 到 1.0 的深度范围。我认为在清除深度缓冲区后立即设置深度范围总是更好,我曾经在清除深度和颜色缓冲区后进行以下设置。

解决方案:

{
    glClearColor(0.0,0.0,0.0,0.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glDepthRange(0.0, 1.0);
    glDepthMask(GL_TRUE);
}