在OpenGL中检测3D物体上的触摸位置

5
我已经在 中为我的应用程序创建了一个3D物体。该物体类似于人体,可以通过触摸旋转。如何检测触摸在这个3D物体上的位置。也就是说,如果用户触摸头部,我必须检测到它是头部。如果触摸在手上,则必须被识别。即使物体旋转到其他方向,它也应该起作用。我认为需要获取触摸在3D物体上的坐标。
这是我获取视图上触摸位置的方法。
- (void) touchesBegan: (NSSet*) touches withEvent: (UIEvent*) event
{
    UITouch* touch = [touches anyObject];
    CGPoint location  = [touch locationInView: self];
    m_applicationEngine->OnFingerDown(ivec2(location.x, location.y));
}

有人可以帮忙吗?提前感谢!

3个回答

5
忘记RayTracing和其他顶尖算法吧。我们在App Store上的一个应用程序(Iyan 3D)中使用了一个简单的技巧。但是这种技术需要每次旋转场景到一个新角度时进行额外的渲染。将不同的对象(头、手、腿等)以不同的颜色(不是实际颜色,而是唯一的颜色)呈现出来。读取与屏幕位置对应的渲染图像中的颜色。您可以根据颜色找到对象。
在这种方法中,您可以更改渲染图像的分辨率以平衡准确性和性能。

+1 - 这是一种非常简单易行的技术。在这里,您可以找到更多有关Processing(类似于Java)的信息和源代码 - http://wiki.processing.org/w/Picking_with_a_color_buffer - cyriel
搜索渲染到纹理进行渲染。然后你就可以很容易地找到颜色。https://dev59.com/zmoy5IYBdhLWcg3wnPOJ - codetiger
这是正确的答案。请确保关闭光照效果,比如环境/高光照明。 - Jason
我的对象根据要求只有一种颜色,无法以不同的颜色渲染它。 - iOS Developer
@codetiger 好的,我会尝试这个方法。由于我是新手,需要在实施之前进行研究。感谢您提供的信息。 - iOS Developer
显示剩余3条评论

3
为了确定物体的3D位置,我建议使用光线追踪。假设模型在世界坐标系中,您还需要知道眼睛位置和图像平面的世界坐标。使用这两个点,您可以计算一条射线,您将使用它与模型相交,我假设模型由三角形组成。
然后,您可以使用射线三角形测试来确定碰触的3D位置,通过找到最接近图像平面的相交三角形。如果您想知道被触摸的三角形,您还需要保存当您进行相交测试时的信息。
此页面提供了如何进行射线三角形相交测试的示例:http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-9-ray-triangle-intersection/ray-triangle-intersection-geometric-solution/ 编辑: 更新为一些示例代码。这是我从一段时间之前做的C++光线追踪项目中获取的一些稍微修改过的代码,因此您需要对其进行一些修改才能使其适用于iOS。此外,当前形式的代码甚至都不会有用,因为它不返回实际的交点,而只是确定射线是否与三角形相交。
// d is the direction the ray is heading in
// o is the origin of the ray
// verts is the 3 vertices of the triangle
// faceNorm is the normal of the triangle surface
bool
Triangle::intersect(Vector3 d, Vector3 o, Vector3* verts, Vector3 faceNorm)
{
    // Check for line parallel to plane
    float r_dot_n = (dot(d, faceNorm));

    // If r_dot_n == 0, then the line and plane are parallel, but we need to 
    // do the range check due to floating point precision
    if (r_dot_n > -0.001f && r_dot_n < 0.001f)
        return false;

    // Then we calculate the distance of the ray origin to the triangle plane
    float t = ( dot(faceNorm, (verts[0] - o)) / r_dot_n);
    if (t < 0.0)
        return false;

    // We can now calculate the barycentric coords of the intersection
    Vector3 ba_ca = cross(verts[1]-verts[0], verts[2]-verts[0]);
    float denom = dot(-d,  ba_ca);

    dist_out = dot(o-verts[0], ba_ca) / denom;
    float b = dot(-d, cross(r.o-verts[0], verts[2]-verts[0])) / denom;
    float c = dot(-d, cross(verts[1]-verts[0], o-verts[0])) / denom;

    // Check if in tri or if b & c have NaN values
    if (  b < 0 || c < 0 || b+c > 1 || b != b || c != c)
        return false;

    // Use barycentric coordinates to calculate the intersection point
    Vector3 P = (1.f-b-c)*verts[0] + b*verts[1] + c*verts[2];

    return true;
}

您所关心的实际交点是P。

我能获取使用此射线三角形相交在iOS中的任何示例代码吗? - iOS Developer
我添加了一些示例代码,列出了需要进行的计算。它是用C++编写的,因为我从我的旧项目中取出来的,但应该很容易理解。此外,函数的返回值不是您要查找的内容,但在函数的末尾计算了交点,因此您应该能够将其转换为对自己有用的格式。 - illeyezur
dist_out 是什么?!? - IOviSpot
什么是 r !?!?!? - IOviSpot

2
射线追踪是一种选项,用于许多应用程序来执行拾取操作。射线追踪的问题在于,这种解决方案需要大量工作才能使一个相当简单的基本功能正常运行。此外,射线追踪可能会很慢,但如果您只有一个要跟踪的射线(比如手指位置),那么速度应该还可以接受。
OpenGL的API也提供了一种选择对象的技术。我建议您查看例如:http://www.lighthouse3d.com/opengl/picking/ 最后,最后一个选项将包括将对象的顶点投影到屏幕空间,并使用简单的2D技术找出您的手指重叠的对象面。

ES并没有提供拾取API,但可以通过每个多边形渲染一个唯一的颜色并使用glReadPixels来获取触摸位置的颜色,或者通过使用带有孔的非常接近表面的绘画和继续使用分割几何和遮挡查询(如果我没记错的话,这在iOS 5中已经提供了)来设计一个稍微复杂但可能更有效的系统。如果线段是封闭的,则可以通过将覆盖物放在背景中并反转深度测试来在绘制时执行遮挡。 - Tommy

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