在过去的几天里,我一直在努力将应用程序的触摸事件"取消投影"到渲染器的坐标空间中。为了实现这一目标,我尝试了各种自定义的取消投影方法和替代技术(包括尝试使用比例因子和转换值转换坐标)无休止。我已经接近了(我的触摸稍微偏离了),但是我使用GLU.gluUnProject
的尝试已经偏离了,通常将坐标放在视图的中心周围。"最接近"的结果是由Xandy的方法产生的,但即使是这些结果通常也是关闭的。我的主要问题是如何设置我的视口矩阵GLU.gluUnProject
我是否传递了正确的参数?我的数学是基于这个问题的答案。以下是我的代码的相关摘录(显示我如何设置矩阵和当前尝试):
public void onSurfaceChanged(GL10 gl, int width, int height) {
// Set the OpenGL viewport to fill the entire surface.
glViewport(0, 0, width, height);
...
float ratio = (float) width / height;
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}
public void onDrawFrame(GL10 gl) {
glClear(GL_COLOR_BUFFER_BIT);
Matrix.setLookAtM(mViewMatrix, 0, 0f, 0f, -4.5f, 0f, 0f, 0f, 0f, 1f, 0f);
Matrix.scaleM(mViewMatrix, 0, mScaleFactor, mScaleFactor, 1.0f);
Matrix.translateM(mViewMatrix, 0, -mOffset.x, mOffset.y, 0.0f);
Matrix.multiplyMM(mModelMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
...
}
public PointF convertScreenCoords(float x, float y) {
int[] viewPortMatrix = new int[]{0, 0, (int)mViewportWidth, (int)mViewportHeight};
float[] outputNear = new float[4];
float[] outputFar = new float[4];
y = mViewportHeight - y;
int successNear = GLU.gluUnProject(x, y, 0, mModelMatrix, 0, mProjectionMatrix, 0, viewPortMatrix, 0, outputNear, 0);
int successFar = GLU.gluUnProject(x, y, 1, mModelMatrix, 0, mProjectionMatrix, 0, viewPortMatrix, 0, outputFar, 0);
if (successNear == GL_FALSE || successFar == GL_FALSE) {
throw new RuntimeException("Cannot invert matrices!");
}
convert4DCoords(outputNear);
convert4DCoords(outputFar);
float distance = outputNear[2] / (outputFar[2] - outputNear[2]);
float normalizedX = (outputNear[0] + (outputFar[0] - outputNear[0]) * distance);
float normalizedY = (outputNear[1] + (outputFar[1] - outputNear[1]) * distance);
return new PointF(normalizedX, normalizedY);
}
convert4DCoords
只是一个辅助函数,它将数组的每个坐标(x,y,z)除以w。 mOffset
和mScaleFactor
是平移和缩放参数(由我们GLSurfaceView
中的ScaleGestureDetector
给出)
根据我阅读的所有内容,这应该可以工作,但它始终是错误的,我不确定还能尝试什么。任何帮助/反馈将不胜感激!
我没有看过你所有的数学,但你的一些矩阵运算和规范对我来说是错误的。这很可能至少是您问题的一部分。
先看看你所说的mViewMatrix
:
Matrix.setLookAtM(mViewMatrix, 0, 0f, 0f, -4.5f, 0f, 0f, 0f, 0f, 1f, 0f);
Matrix.scaleM(mViewMatrix, 0, mScaleFactor, mScaleFactor, 1.0f);
Matrix.translateM(mViewMatrix, 0, -mOffset.x, mOffset.y, 0.0f);
这并不一定有问题。但大多数人可能只会将第一部分称为视图矩阵,这是setLookAtM()
的结果。其余的看起来更像是一个模型矩阵。但由于渲染通常只使用视图和模型矩阵的乘积,所以这只是术语。可以公平地说,您存储在mViewMatrix
中的是您的模型视图矩阵。
然后这里的命名变得更加奇怪:
Matrix.multiplyMM(mModelMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
这将计算投影和视图矩阵的乘积。所以这将是一个ViewProjection 矩阵。将其存储在名为 mModelMatrix
的变量中是令人困惑的,我认为您可能已经用这个命名为自己设置了一个陷阱。
这让我们想到了glUnproject()
电话:
GLU.gluUnProject(x, y, 0, mModelMatrix, 0, mProjectionMatrix, 0, viewPortMatrix, 0, outputNear, 0);
基于上述内容,您为两个矩阵参数(视口不是真正的矩阵)传递的是 ViewProjection 和投影矩阵。根据方法定义,应传递模型视图和投影矩阵。
由于我们确定您所谓的mViewMatrix
对应于 ModelView 矩阵,因此如果您仅更改该参数,这将开始更好地工作:
GLU.gluUnProject(x, y, 0, mViewMatrix, 0, mProjectionMatrix, 0, viewPortMatrix, 0, outputNear, 0);
然后,您可以摆脱根本不是模型矩阵的mModelMatrix
。