我在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是否反转?这可以解释这个问题......
答案 0 :(得分:1)
不,它们在技术上并不倒置。可能发生的是你正在使用来自窗口系统的输入坐标(几乎总是用(0,0)定义为左上角),如果你使用OpenGL倾向于使(0,0)左下角传统的投影矩阵。
在传统的固定功能OpenGL管道中,投影前后应用不同的坐标惯用惯例。坐标是右手(对象/世界/视图空间),但随后投影矩阵翻转Z轴,结果是顶点变换后的左手坐标系(剪辑/ NDC /窗口空间)。 / p>
嗯,事实证明,如果你修改你的投影矩阵,使得Y = 0是屏幕的顶部而不是底部,你实际上引入了另一种手性变化。无论何时在坐标系中翻转轴,都会产生无法通过任何旋转或平移组合复制的镜像;在数学方面,我们称之为chirality。
<小时/>
重新定义投影矩阵,以便在从窗口的顶部移动到底部时Y轴向正方向移动
反转窗口系统提供给您的Y坐标
<小时/>
正如我前面提到的,如果你在投影矩阵中重新定义一个轴,你将改变后投影坐标空间的惯性。这意味着依赖于缠绕方向的光栅化操作将全部向后(例如,曾经被缠绕的东西GL_CCW
现在将被缠绕GL_CW
)并且如果您不通过改变{{1}来补偿这一点然后前/后着色,剔除等将无法按预期工作。
这种方法到目前为止比较简单,但你必须经常意识到窗口管理器和OpenGL使用的坐标系是不兼容的。您必须记住,在使用它们引用OpenGL窗口空间中的某个点之前,始终将输入事件的坐标翻转过来。
这一切都取决于您使用直接来自窗口系统的坐标的频率(例如来自输入事件)。 OpenGL对纹理原点使用相同的约定((0,0)是纹理图像的左下角)所以你可能希望对此做一个心理记录。我个人会以他们的方式离开OpenGL的坐标系,并通过翻转Y来转换窗口系统坐标。