如何确定屏幕上触摸的内容在3D空间中的位置?

6

如何在我的OpenGL ES 1.1 Android应用程序中使用gl.gluUnproject来确定用户触摸屏幕时选择了什么?

我的理解是触摸事件会产生一条线,我必须找到它与第一个“物体”相交的位置。

有没有关于如何做到这一点的教程?

4个回答

4
如果你正在进行2D到3D的拾取,你需要稍微调整矩阵和向量。OpenGL ES 1.1中没有GlUnproject,所以你需要自己进行一些数学计算。
那么,射线-物体相交就是一个好方法。Timmmms的回答已经涵盖了其中的一部分,但还有更多。想法是从2D坐标创建出一条射线到3D空间。为此需要视图矩阵和投影矩阵的逆矩阵。一旦你有了射线,你可以使用你选择的射线相交测试,当然你需要像在Timmmm的第4点一样选择最近的物体。边界球和边界框很容易实现,而且互联网上充满了它们的相交测试教程。 这个拾取教程是针对DirectX的,但你可能会得到灵感。射线构建部分是最重要的。

编辑 Android实现了自己的gluUnproject版本。可以通过调用它来创建射线,为近和远平面(0和1)分别调用它,并从远平面结果中减去近平面结果以获得射线方向。射线起点是视图位置。更多信息


我曾经认为它支持gluUnProject(): http://developer.android.com/reference/android/opengl/GLU.html - Alexander Trauzzi
1
哦,确实Android似乎实现了它自己的版本。无论如何,它并不是OpenGL ES 1.1的一部分。您可以通过调用该函数两次来使用该函数创建光线:http://www.opengl.org/resources/faq/technical/selection.htm - Virne
你有什么建议可以帮我计算出这条射线与哪些物体相交了吗? - Alexander Trauzzi
http://www.realtimerendering.com/intersections.html 包含教程链接。我建议您从射线-球体相交开始。这是最简单的,也可能足够了。无论您选择什么,都需要访问对象的顶点以及它们的变换矩阵,以计算世界空间中的边界球。也许Android已经有这样的功能。(我从未使用过Android,所以我不知道。) - Virne

2

我认为对于大多数应用程序,您应该选择正确的3D方法:光线投射。

将用户选择的2D屏幕坐标位置投影到您的世界空间中。这会产生一条从相机起始并指向场景的3D射线。现在,您需要在3D中执行碰撞测试。在大多数情况下,这可以通过将对象简化为一组简单的几何形状(例如椭球体、球体和盒子)来加速完成。

鉴于手持设备的精度,这应该已经足够精确了。请注意,根据物体的形式,您可能需要使用多个基本原语。此外,总是使用相同的原语是毫无意义的:显然,包围球是非常长的棒子的一个非常糟糕的近似值。


你知道有没有任何教程可以解释如何进行这些测试吗? - Alexander Trauzzi
1
很遗憾,目前还没有找到一个简明的实现方法。虽然有一些零散的资料,但是并不完整。您需要多快?也许我可以写点东西…… - mnemosyn
我永远不会拒绝制作新的教程!如果你最终制作了一个,我很想看到它在Java+Android的背景下完成! - Alexander Trauzzi
好吧,欢迎你来翻译它。我甚至没有安装Java。问题是涉及到很多代码:射线、向量、矩阵、矩阵求逆等等。我会看看能做些什么… - mnemosyn

1

这完全取决于你正在渲染什么。你可能不应该使用拾取方法,因为:

a) 它听起来会很慢,特别是在安卓上。 b) 你可能想要为小物体提供更大的“触摸区域”,这样你就不必精确地触摸它们所在的位置。 c) 它并没有真正回答正确的问题——它给出了结果“最顶层的图形项是在我触摸的位置上精确渲染的吗?”而你想知道的是“用户触摸或接近了哪个游戏实体?”

正如我所说,这完全取决于你的游戏。如果它是一个2D或几乎是2D的游戏,那么很简单,你只需要将触摸坐标输入到你的游戏模型中。对于3D游戏,我建议使用我刚想出来的这个简单算法:

  1. 列出所有可能被触摸的可触摸游戏对象列表。
  2. 将它们的中心坐标转换为3D屏幕坐标。(2D屏幕坐标描述在这里:http://www.flipcode.com/archives/Plotting_A_3D_Point_On_A_2D_Screen.shtml
  3. 找到每个对象的2D距离,丢弃距离大于您的触摸阈值的对象。
  4. 根据某些距离度量找到最近的对象。此时您需要进行实验,这取决于游戏的性质。

为了得到精确的结果,可以使用线交点算法。有一些算法可以实现这个功能(搜索“平面线交点射线投射”)。


你这样做就默认所有物体的形状相同,并且它们在三维空间中到相机的距离也相同。我认为在大多数情况下这些都不是有效的假设。 - mnemosyn

1

我想到的一个方法是缓存调用gluProject的结果。这可能只适用于处理固定相机时才实际可行。在任何相机视角变化结束时,我可以重新生成这个“可触摸”缓存。

这还有一个额外的好处,就是确保我只测试那些会响应触摸的输入对象。

我很感谢对这种方法的任何想法!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接