0

I am working on an Android Application in which a 3d scene is displayed and the user should be able to select an area by clicking/tapping the screen. The scene is pretty much a planar (game) board on which different objects are placed.
Now, the problem is how do I get the clicked area on the board from the actual screen-space coordinates?

I was planning on using gluUnProject(), as I have access to (almost) all the necessary parameters. Unfortunately I am missing the winZ param, and cannot get the current depth as the touch event is occurring in a different thread than the GL-thread.
My new plan is to still use gluUnProject, but with a winZ of 0, and then project the resulting point onto the board (the board stretches from 0,0,0 to 10,0,10 in model space), However, I can't seem to figure out how to do this?

I would be very happy if anyone could help me out with the maths needed to do this (matrices were never my strongest side), or perhaps find a better solution.

To clarify; here is an image of what I want to do: image
The red rectangle represent the device screen, the green x is the touch event and the black square is the board (grey subdivisions represent a square of one unit). I need to figure out where on the board the touch has happened (in this case it is in square 1,1).

4

2 回答 2

1

由于您基本上已经在 2D 中工作,(我假设您的意思是您的 3D 板从 0,0,0 延伸到 10,10,0 (x,y,z)。)您可以翻译和内插/外推 2D/3D没有 gluUnProject() 的屏幕空间坐标的空间坐标。您将需要您的屏幕分辨率,并选择您希望转换为的 3D 空间网格的分辨率。如果屏幕和 3D 空间原点对齐(0,0 屏幕空间位于 0,0,0 3D 空间),并且您的屏幕尺寸为 320x240,使用现有的 10x10 3D 网格,则 320/10 = 32 和 240 /10 = 24,因此单个 1x1 区域的屏幕空间大小为 32x24。因此,如果用户按下 162、40,则用户在 3D 空间中按下 (5, 1, 0) (162/32 >= 5 but < 6, 40/24 >= 1 but < 2)。如果您需要比这更大的分辨率,您可以选择更高的 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)。尽管它在某些方面可能会使它变得更简单,但我相信从建模的角度来看,您还有额外的工作要做。请注意,像 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)。尽管它在某些方面可能会使它变得更简单,但我相信从建模的角度来看,您还有额外的工作要做。请注意,像 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

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

于 2012-04-03T20:32:46.367 回答
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.
于 2012-04-04T21:31:52.663 回答