反向投影屏幕空间坐标到模型空间坐标

时间:2012-04-03 19:11:10

标签: android opengl-es-2.0 coordinate-transformation

我正在开发一个Android应用程序,其中显示一个3d场景,用户应该可以通过单击/点击屏幕来选择一个区域。场景几乎是一个平面(游戏),在其上放置不同的物体 现在,问题是我如何从实际的屏幕空间坐标获得板上的点击区域?

我打算使用gluUnProject(),因为我可以访问(几乎)所有必要的参数。不幸的是,我错过了winZ param,并且由于触摸事件发生在与GL线程不同的线程中,因此无法获得当前深度。
我的新计划仍然是使用gluUnProject,但winZ为0,然后将结果点投影到板上(板在模型空间中从0,0,0延伸到10,0,10,但是,我似乎无法弄清楚如何做到这一点?

如果有人能帮助我完成这项工作所需的数学(矩阵从来不是我最强的一面),或者找到更好的解决方案,我会很高兴。

澄清;这是我想要做的图像: image
红色矩形表示设备屏幕,绿色x表示触摸事件,黑色正方形表示板(灰色细分表示一个单元的正方形)。我需要弄清楚触摸板发生在哪个位置(在这种情况下,它是方形1,1)。

2 个答案:

答案 0 :(得分:1)

当你基本上已经在2D工作时,(我认为你的意思是你的3D板从0,0,0延伸到10,10,0(x,y,z)。)你可以翻译和插值/推断没有gluUnProject()的屏幕空间坐标中的2D / 3D空间坐标。您将需要屏幕分辨率,并选择要转换为的3D空间网格的分辨率。如果屏幕和3D空间原点对齐(0,0屏幕空间为0,0,0 3D空间),并且屏幕尺寸为320x240,则使用现有的10x10 3D网格,然后320/10 = 32和240 / 10 = 24,因此单个1x1区域的屏幕空间大小为32x24。因此,如果用户按下162,40,则用户按下(5,1,0)(162/32> = 5但是< 6,40 / 24> = 1但是< 2) 3D空间。如果您需要更高的分辨率,则可以选择更高的3D空间网格分辨率(即使用20而不是10)。您无需更新GL矩阵即可使用此因子。虽然它可能会在某些方面变得更简单,但我确信从建模角度来看,您还有其他工作要做。只要知道像20这样的因素,1,3就是(.5,1.5,0)。如果您的屏幕和3D空间原点尚未对齐,则需要在此之前翻译屏幕空间坐标。如果0,0屏幕空间为10,10,0,则需要获取屏幕分辨率并从中减去当前点,在此示例中将0,0设为320,240,我们的示例点为162,40,是158(320-158 == 162),200(240-200 == 40)。

如果您想了解投影矩阵的概述以及它们如何工作,这可以帮助您了解将屏幕空间维度放在非项目矩阵中的位置,请阅读OpenGL红皮书的这一章。 http://www.glprogramming.com/red/chapter03.html

希望这有帮助,祝你好运!

答案 1 :(得分:0)

所以,我设法通过以下方式解决了这个问题:

float[] clipPoint = new float[4];
int[] viewport = new int[]{0, 0, width, height};

//screenY/screenX are the screen-coordinates, y should be flipped:
screenY = viewport[3] - screenY;

//Calculate a z-value appropriate for the far clip:
float dist = 1.0f;
float z = (1.0f/clip[0] - 1.0f/dist)/(1.0f/clip[0]-1.0f/clip[1]);

//Use gluUnProject to create a 3d point in the far clip plane:
GLU.gluUnProject(screenX, screenY, z, vMatrix, 0, pMatrix, 0, viewport, 0, clipPoint, 0);

//Get a point representing the 'camera':
float eyeX = lookat[0] + eyeOffset[0]; 
float eyeY = lookat[1] + eyeOffset[1];
float eyeZ = lookat[2] + eyeOffset[2];

//Do some magic to calculate where the line between clipPoint and eye/camera would intersect the y-plane:
float dX = eyeX - clipPoint[0];
float dY = eyeY - clipPoint[1];
float dZ = eyeZ - clipPoint[2];

float resX = glu[0] - (dX/dY)*glu[1];
float resZ = glu[2] - (dZ/dY)*glu[1];
//resX and resZ is the wanted result.