gluUnProject并在固定z上找到点(OpenGL ES 2.0 android)

时间:2013-12-30 12:34:04

标签: android opengl-es-2.0

我在OpenGL场景中找到点击的点有问题。每当我缩放或旋转屏幕时,我的视图矩阵都会被修改(我在这里添加了包含所有视图参数的版本):

            final float eyeX = 0.0f;
            final float eyeY = -5.0f;
            final float eyeZ = 25.0f - zoom;

            final float centerX = 0.0f;
            final float centerY = 0.0f;
            final float centerZ = -9.0f;

            final float upX = 0.0f;
            final float upY = 1.0f;
            final float upZ = 0.0f;

            Matrix.setLookAtM(viewMatrix, 0, eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
            Matrix.rotateM(viewMatrix, 0, rotateAngle, 0, 0, 1.0f);

当我绘制各种模型时,它的工作非常完美,所有模型都能正确缩放和旋转。 但是当我尝试使用gluUnProject函数找到点击点时,只有当rotationAngle为零并且zoom也很小时,这些值似乎是正确的(只有y值反转)。我的变焦范围从1到25不等。 点查找功能如下所示:

public PointF getPoint(float touchX, float touchY) {

    int[] view = new int[] { 0, 0, screenWidth, screenHeight };
    float[] obj = new float[8];
    GLU.gluUnProject(touchX, touchY, -1.0f, viewMatrix, 0,
            projectionMatrix, 0, view, 0, obj, 0);
    GLU.gluUnProject(touchX, touchY, 1.0f, viewMatrix, 0,
            projectionMatrix, 0, view, 0, obj, 4);
    float x1 = obj[0] / obj[3];
    float y1 = obj[1] / obj[3];
    float z1 = obj[2] / obj[3];
    float x2 = obj[4] / obj[7];
    float y2 = obj[5] / obj[7];
    float z2 = obj[6] / obj[7];

    float t = (-10 - z1) / (z1 - z2);
    float x = x1 + t * x1 - t * x2;
    float y = y1 + t * y1 - t * y2;

    return new PointF(x, y);
}

我在这里只使用视图矩阵,我的模型矩阵在这里是标识。这是错误的方法吗?此外,我试图找到只有点的x和y坐标,z是固定的并且等于-10(这就是为什么-10是硬编码的)。

修改

好的,似乎问题解决了......我修改了getPoint函数:

public PointF getPoint(float touchX, float touchY) {

    float[] almostViewM = new float[16];
    Matrix.setLookAtM(almostViewM, 0, 0.0f, 5.0f, 25.0f - scaleFactor, 0.0f, 0.0f,
            -9.0f, 0.0f, 1.0f, 0.0f);

    Matrix.rotateM(almostViewM, 0, -rotateAngle, 0, 0, 1.0f);       

    int[] view = new int[] { 0, 0, screenWidth, screenHeight };
    float[] obj = new float[8];
    GLU.gluUnProject(touchX, touchY, -1.0f, almostViewM, 0,
            projectionMatrix, 0, view, 0, obj, 0);
    GLU.gluUnProject(touchX, touchY, 1.0f, almostViewM, 0,
            projectionMatrix, 0, view, 0, obj, 4);
    float x1 = obj[0] / obj[3];
    float y1 = obj[1] / obj[3];
    float z1 = obj[2] / obj[3];
    float x2 = obj[4] / obj[7];
    float y2 = obj[5] / obj[7];
    float z2 = obj[6] / obj[7];

    float t = (-10 - z1) / (z2 - z1);
    float x = x1 + t * x2 - t * x1;
    float y = -(y1 + t * y2 - t * y1);

    return new PointF(x, y);
}

我“伪造”了我的视图矩阵,将eyeY切换为-eyeY值并将rotateAngle设置为-rotateAngle。然后,我添加 - 结果y值... 它现在有效。不过,我不知道为什么会这样。对于OpenGL 2.0和GLU,y coords和angle是否反转?这可以解释这个问题......

1 个答案:

答案 0 :(得分:1)

不,它们在技术上并不倒置。可能发生的是你正在使用来自窗口系统的输入坐标(几乎总是用(0,0)定义为左上角),如果你使用OpenGL倾向于使(0,0)左下角传统的投影矩阵。

在传统的固定功能OpenGL管道中,投影前后应用不同的坐标惯用惯例。坐标是右手(对象/世界/视图空间),但随后投影矩阵翻转Z轴,结果是顶点变换后的左手坐标系(剪辑/ NDC /窗口空间)。 / p>

在这个问题中,翻转Z轴与Y轴有什么关系?

嗯,事实证明,如果你修改你的投影矩阵,使得Y = 0是屏幕的顶部而不是底部,你实际上引入了另一种手性变化。无论何时在坐标系中翻转轴,都会产生无法通过任何旋转或平移组合复制的镜像;在数学方面,我们称之为chirality

<小时/>

实际上有两种方法可以解决这个问题:

  1. 重新定义投影矩阵,以便在从窗口的顶部移动到底部时Y轴向正方向移动

  2. 反转窗口系统提供给您的Y坐标

  3. <小时/>

    选项1

    正如我前面提到的,如果你在投影矩阵中重新定义一个轴,你将改变后投影坐标空间的惯性。这意味着依赖于缠绕方向的光栅化操作将全部向后(例如,曾经被缠绕的东西GL_CCW现在将被缠绕GL_CW)并且如果您不通过改变{{1}来补偿这一点然后前/后着色,剔除等将无法按预期工作。

    选项2

    这种方法到目前为止比较简单,但你必须经常意识到窗口管理器和OpenGL使用的坐标系是不兼容的。您必须记住,在使用它们引用OpenGL窗口空间中的某个点之前,始终将输入事件的坐标翻转过来。


    这一切都取决于您使用直接来自窗口系统的坐标的频率(例如来自输入事件)。 OpenGL对纹理原点使用相同的约定((0,0)是纹理图像的左下角)所以你可能希望对此做一个心理记录。我个人会以他们的方式离开OpenGL的坐标系,并通过翻转Y来转换窗口系统坐标。