我最近几天一直在努力将我们应用程序的触摸事件“取消投影”到我们的渲染器坐标空间。为了实现这一目标,我尝试了各种自定义非项目方法和替代技术(包括尝试使用缩放因子和变换值将坐标转换为无)。我已经接近了(我的触摸稍微偏离了)但是我使用GLU.gluUnProject
的尝试已经方式关闭,通常将坐标放在视图的中心周围。 “最接近”的结果由Xandy's method产生,但即使这些结果通常都是关闭的。我的主要问题是如何设置我的视口矩阵,我是否传递了GLU.gluUnProject
正确的参数?我的数学基于this question的答案。以下是我的代码的相关摘录(显示我如何设置我的矩阵和我当前的尝试):
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
是翻译和缩放参数(由ScaleGestureDetector
中的GLSurfaceView
提供)
根据我读过的所有内容应该正在运行,但它始终是错误的,我不知道还有什么可以尝试。任何帮助/反馈将不胜感激!
答案 0 :(得分:0)
我没有查看你的所有数学,但是你的一些矩阵操作和规范看起来不对。这很可能至少是你问题的一部分。
首先看一下你所说的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()
的结果,即View矩阵。其余的看起来更像是一个模型矩阵。但由于渲染通常只使用View和Model矩阵的产品,因此这只是术语。可以公平地说,你在mViewMatrix
中存储的是你的ModelView矩阵。
然后命名在这里变得陌生:
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和Projection矩阵。基于方法定义,您应该传递ModelView和Projection矩阵。
由于我们确定你所谓的mViewMatrix
对应于一个ModelView矩阵,如果只改变那个参数,这应该会更好地开始工作:
GLU.gluUnProject(x, y, 0, mViewMatrix, 0, mProjectionMatrix, 0, viewPortMatrix, 0, outputNear, 0);
然后你可以完全摆脱不是模型矩阵的mModelMatrix
。