【问题标题】:gluUnProject returns an inaccurate z coordinate under some conditionsgluUnProject 在某些情况下返回不准确的 z 坐标
【发布时间】:2013-01-09 12:54:21
【问题描述】:

我在使用 gluUnProject 时遇到了一些问题,因为我检索到的 Z 坐标不准确。

所涉及的程序本质上是一个 3d 查看器。我实现了一个小功能,允许用户单击加载的模型并检索两点之间的距离。

这是代码:

//  Declare variables for viewport, modelview and projection matrix
int viewport[] = new int[4];
float modelview[] = new float[16];
float projection[] = new float[16];
//  GL y-coordinate position
int realY;
//  Returned [wx, wy, wz, 1] coordinates
float worldCoordinates[] = new float[4];

gl2.glGetIntegerv(GL2.GL_VIEWPORT, viewport, 0);
gl2.glGetFloatv(GL2.GL_MODELVIEW_MATRIX, modelview, 0);
gl2.glGetFloatv(GL2.GL_PROJECTION_MATRIX, projection, 0);

//  Retrive the Y coordinate, note viewport[3] is height of window in pixels
realY = viewport[3] - click.y - 1;

//  Allocate a buffer to store the result
FloatBuffer fb = FloatBuffer.allocate(1);

//  Retrieve the Z coordinate, read a block of pixels from the frame buffer
gl2.glReadPixels(click.x, realY, 1, 1, GL2.GL_DEPTH_COMPONENT, GL2.GL_FLOAT, fb);

System.out.println("Depth: "+fb.get(0));

//  Avoid centering if the click is on nothing
if (fb.get(0) == 1.0f) {
    return null;
}
//  Map window coordinates to object coordinates, retrieve the world coordinates
glu.gluUnProject(click.x, realY, fb.get(0), modelview, 0, projection, 0,
            viewport, 0, worldCoordinates, 0);

当我测量位于与用户垂直的表面上的两点之间的距离时,一切正常。如果我们想象一个 3 轴系统,z 指向用户,y 指向顶部,这两个点位于 XY 平面上。无论围绕 Z 旋转如何,它都能正常工作。

例如,这里我创建了一个小正方形平面,两个点的高度相同(一个被标签遮挡):

世界坐标P1:(0.019062456, 0.03357359, 0.08333321, 1)

世界坐标P2:(0.025983132, 0.028048635, 0.08333321, 1)

但如果我在全局 X 轴上旋转整个场景,则检索到的 Z 坐标会发生变化:

X 和 Y 坐标无关紧要,重要的是 Z 坐标。它不再是 0.08333321。

世界坐标P1:(0.026863147, 0.027185505, 0.0831252, 1)

世界坐标P2:(0.020072304, 0.034560144, 0.08312501, 1)

此外,在全局 X 上旋转后,缩放也会影响点的 Z 坐标。

Ps:我正在使用 JOGL。通过放大/缩小 glOrtho 平行六面体来执行放大和缩小。 glReadPixels 生成的 Z 深度 fb.get(0) 包含在 [0, 1] 中。

我哪里错了?

【问题讨论】:

    标签: opengl rotation coordinate-systems depth glu


    【解决方案1】:

    您是否希望在您的飞机上看到该点的确切坐标?你不会这样理解的。

    当您渲染您的正方形时,坐标会被转换为 3D,然后将图元栅格化(即转换为 2D 并进行插值),生成屏幕 X、Y 和(通常)24 位深度值。这是相当大的精度损失(甚至不是线性的),所以如果你读取它并反转变换,你得到的只是原始值的近似值。

    如果您的多边形恰好垂直于视图方向,则插值至少会在整个表面上提供一致的 z 值(因为所有转换后的 Z 值都相同),尽管它不一定是 right z 值。所以深度的任何变化都会导致误差变化,如果你的平面不垂直,它甚至会在多边形上保持一致。

    深度基本上足以在没有太多错误的情况下进行绘制(即使如此,也并非总是如此),但对于重建精确的几何图形却不是​​这样。

    如果您想要更好的结果,您可以将实际模型空间 X、Y、Z 光栅化为带有着色器的(浮动)FBO,然后将其读回。或者,在软件中将射线与您的几何体相交。

    【讨论】:

    • 感谢 JasonD 的回答,它证实了我的主要恐惧:近似/插值错误。但是,仅仅是浮动 FBO 就足以改善这种情况吗?如何查看我目前使用的是哪一个?
    • 如果你没有明确地创建一个 FBO,你只会渲染到窗口。所以可能只是一个 8 位的每通道缓冲区。无论如何,我建议一个额外的缓冲区,它可以直接以更合适的格式和空间存储您需要的信息。是否值得(或是否足够)取决于您的具体要求。
    • 不,我使用的是 opengl 默认的 FBO。所以你建议我用一些特定的格式(浮点数)创建一个额外的 FBO。我现在正在谷歌搜索,但我找不到对我的目的有用/特定的东西,你有没有关于这个的好链接? (创建浮动 FBO)
    • 我手头没有任何东西,尽管我过去在需要与您的情况类似的东西时做过。我使用的是完整的 4 通道浮点 FBO,GL_RGBA32F。它们非常大,但如果您只是抓取单个像素,您可能只需要渲染显示的子集。
    猜你喜欢
    • 2015-08-03
    • 1970-01-01
    • 1970-01-01
    • 2010-12-31
    • 2016-09-08
    • 1970-01-01
    • 2022-07-01
    • 2012-12-29
    • 2019-12-27
    相关资源
    最近更新 更多