光线投射 - 在 OpenGL ES (Rajawali3D) 中将屏幕上的触摸转换为球体上的点
Raycasting - Convert touch on screen to point on sphere in OpenGL ES (Rajawali3D)
我有一个使用 Rajawali3D OpenGL ES 库创建的球体,相机位于球体内 (0, 0, 0)
。用户可以在滑动时旋转此球体。
我想获取用户在球体上触摸的点的 3D 坐标
目前我正在使用Unproject
方法获取近平面和远平面,计算矢量方向并找到sphere.Here中的交点是代码
mNearPos4 = new double[4];
mFarPos4 = new double[4];
mNearPos = new Vector3();
mFarPos = new Vector3();
mNewPos = new Vector3();
// near plane
GLU.gluUnProject(x, getViewportHeight() - y, 0,
mViewMatrix.getDoubleValues(), 0,
mProjectionMatrix.getDoubleValues(), 0, mViewport, 0,
mNearPos4, 0);
// far plane
GLU.gluUnProject(x, getViewportHeight() - y, 1.0f,
mViewMatrix.getDoubleValues(), 0,
mProjectionMatrix.getDoubleValues(), 0, mViewport, 0,
mFarPos4, 0);
// transform 4D to 3D
mNearPos.setAll(mNearPos4[0] / mNearPos4[3], mNearPos4[1]
/ mNearPos4[3], mNearPos4[2] / mNearPos4[3]);
mFarPos.setAll(mFarPos4[0] / mFarPos4[3],
mFarPos4[1] / mFarPos4[3], mFarPos4[2] / mFarPos4[3]);
Vector3 dir = new Vector3(mFarPos.x - mNearPos.x, mFarPos.y - mNearPos.y, mFarPos.z - mNearPos.z);
dir.normalize();
// compute the intersection with the sphere centered at (0, 0, 0)
double a = Math.pow(dir.x, 2) + Math.pow(dir.y, 2) + Math.pow(dir.z, 2);
double b = 2 * (dir.x * (mNearPos.x) + dir.y * (mNearPos.y) + dir.z * (mNearPos.z));
double c = Math.pow(mNearPos.x, 2) + Math.pow(mNearPos.y, 2) + Math.pow(mNearPos.z, 2) - radSquare;
double D = Math.pow(b, 2) - 4 * a * c;
// need only smaller root since the camera is within
// mNewPos is used as the position of the point
mNewPos.setAll((mNearPos.x + dir.x * t), (mNearPos.y + dir.y * t), mNearPos.z);
问题是我在旋转球体时得到了相同范围的坐标。例如,如果我在球体的一侧得到坐标 (a, b, c)
,我在球体的另一侧得到相同的坐标。
我该如何解决这个问题并获得所有边的正确坐标?
我正在使用 Rajawali 1.0.232 快照
已解决:问题是我将相机的投影和视图矩阵保存在变量中。
因此,当调用 unproject() 将 2D 点转换为 3D 时,它采用的是旧值,因此无法正确绘制点。
所以一个解决方案是按需获取相机的视图和投影矩阵而不缓存它们。
mViewport = new int[]{0, 0, getViewportWidth(), getViewportHeight()};
Vector3 position3D = new Vector3();
mapToSphere(event.getX(), event.getY(), position3D, mViewport,
mCam.getViewMatrix(), mCam.getProjectionMatrix());
其中 mapSphere() 函数按如下方式执行取消投影功能
public static void mapToSphere(float x, float y, Vector3 position, int[] viewport,
Matrix4 viewMatrix, Matrix4 projectionMatrix) {
//please refer for explanation in case of openGL
//http://myweb.lmu.edu/dondi/share/cg/unproject-explained.pdf
double[] tempPosition = new double[4];
GLU.gluUnProject(x, viewport[3] - y, 0.7f,
viewMatrix.getDoubleValues(), 0,
projectionMatrix.getDoubleValues(), 0, viewport, 0,
tempPosition, 0);
// the co-ordinates are stored in tempPosition as 4d (x, y, z, w)
// convert to 3D by dividing x, y, z by w
// the minus (-) for the z co-ordinate worked for me
position.setAll(tempPosition[0] / tempPosition[3], tempPosition[1]
/ tempPosition[3], -tempPosition[2] / tempPosition[3]);
}
我有一个使用 Rajawali3D OpenGL ES 库创建的球体,相机位于球体内 (0, 0, 0)
。用户可以在滑动时旋转此球体。
我想获取用户在球体上触摸的点的 3D 坐标
目前我正在使用Unproject
方法获取近平面和远平面,计算矢量方向并找到sphere.Here中的交点是代码
mNearPos4 = new double[4];
mFarPos4 = new double[4];
mNearPos = new Vector3();
mFarPos = new Vector3();
mNewPos = new Vector3();
// near plane
GLU.gluUnProject(x, getViewportHeight() - y, 0,
mViewMatrix.getDoubleValues(), 0,
mProjectionMatrix.getDoubleValues(), 0, mViewport, 0,
mNearPos4, 0);
// far plane
GLU.gluUnProject(x, getViewportHeight() - y, 1.0f,
mViewMatrix.getDoubleValues(), 0,
mProjectionMatrix.getDoubleValues(), 0, mViewport, 0,
mFarPos4, 0);
// transform 4D to 3D
mNearPos.setAll(mNearPos4[0] / mNearPos4[3], mNearPos4[1]
/ mNearPos4[3], mNearPos4[2] / mNearPos4[3]);
mFarPos.setAll(mFarPos4[0] / mFarPos4[3],
mFarPos4[1] / mFarPos4[3], mFarPos4[2] / mFarPos4[3]);
Vector3 dir = new Vector3(mFarPos.x - mNearPos.x, mFarPos.y - mNearPos.y, mFarPos.z - mNearPos.z);
dir.normalize();
// compute the intersection with the sphere centered at (0, 0, 0)
double a = Math.pow(dir.x, 2) + Math.pow(dir.y, 2) + Math.pow(dir.z, 2);
double b = 2 * (dir.x * (mNearPos.x) + dir.y * (mNearPos.y) + dir.z * (mNearPos.z));
double c = Math.pow(mNearPos.x, 2) + Math.pow(mNearPos.y, 2) + Math.pow(mNearPos.z, 2) - radSquare;
double D = Math.pow(b, 2) - 4 * a * c;
// need only smaller root since the camera is within
// mNewPos is used as the position of the point
mNewPos.setAll((mNearPos.x + dir.x * t), (mNearPos.y + dir.y * t), mNearPos.z);
问题是我在旋转球体时得到了相同范围的坐标。例如,如果我在球体的一侧得到坐标 (a, b, c)
,我在球体的另一侧得到相同的坐标。
我该如何解决这个问题并获得所有边的正确坐标?
我正在使用 Rajawali 1.0.232 快照
已解决:问题是我将相机的投影和视图矩阵保存在变量中。
因此,当调用 unproject() 将 2D 点转换为 3D 时,它采用的是旧值,因此无法正确绘制点。
所以一个解决方案是按需获取相机的视图和投影矩阵而不缓存它们。
mViewport = new int[]{0, 0, getViewportWidth(), getViewportHeight()};
Vector3 position3D = new Vector3();
mapToSphere(event.getX(), event.getY(), position3D, mViewport,
mCam.getViewMatrix(), mCam.getProjectionMatrix());
其中 mapSphere() 函数按如下方式执行取消投影功能
public static void mapToSphere(float x, float y, Vector3 position, int[] viewport,
Matrix4 viewMatrix, Matrix4 projectionMatrix) {
//please refer for explanation in case of openGL
//http://myweb.lmu.edu/dondi/share/cg/unproject-explained.pdf
double[] tempPosition = new double[4];
GLU.gluUnProject(x, viewport[3] - y, 0.7f,
viewMatrix.getDoubleValues(), 0,
projectionMatrix.getDoubleValues(), 0, viewport, 0,
tempPosition, 0);
// the co-ordinates are stored in tempPosition as 4d (x, y, z, w)
// convert to 3D by dividing x, y, z by w
// the minus (-) for the z co-ordinate worked for me
position.setAll(tempPosition[0] / tempPosition[3], tempPosition[1]
/ tempPosition[3], -tempPosition[2] / tempPosition[3]);
}