【问题标题】:Detecting touch position on 3D objects in openGL在openGL中检测3D对象上的触摸位置
【发布时间】:2013-08-08 12:06:45
【问题描述】:

我在 中为我的一个应用程序创建了一个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));
}

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

【问题讨论】:

    标签: opengl iphone objective-c opengl-es 3d


    【解决方案1】:

    忘掉光线追踪和其他顶尖算法吧。我们在 App Store 上为我们的一个应用程序(Iyan 3D)使用了一个简单的技巧。但是,每次将场景旋转到一个新角度时,这种技术都需要一个额外的渲染通道。以不同的颜色(不是实际的颜色,而是独特的颜色)渲染不同的对象(头部、手、腿等)。读取渲染图像中与屏幕位置对应的颜色。您可以根据其颜色找到对象。

    在此方法中,您可以使用更改渲染图像分辨率来平衡准确性和性能。

    【讨论】:

    • +1 - 这是非常简单且易于实施的技术。在这里你有更多的信息和源代码处理(类似Java) - wiki.processing.org/w/Picking_with_a_color_buffer
    • 搜索渲染到纹理进行渲染。那么你应该很容易找到颜色。 stackoverflow.com/questions/8439697/…
    • 这是正确答案。确保关闭照明效果,例如环境/镜面照明
    • 您只需要在顶点着色器中计算顶点位置并在片段着色器中输入相应的颜色值。 RTT 简单易行。您可以通过使用 2048x2048 来提高准确度,但这对于检测触摸来说太过分了。我们使用了 1024x512,效果很好。
    • 我的对象按要求只有单一颜色。不能用不同的颜色渲染它。
    【解决方案2】:

    为了确定物体的 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 中使用这个射线三角形交点吗?
    • 我添加了一些示例代码,其中列出了需要进行的计算。它在 C++ 中,因为我从我的一个旧项目中获取它,但它应该很容易理解。此外,函数的返回值不是您要查找的值,而是计算函数末尾的交点,因此您应该能够将其转换为对自己有用的格式。
    • 什么是 dist_out !?!?
    • 什么是 r !?!?!?
    【解决方案3】:

    光线追踪是一种选择,在许多应用程序中都用于实现这一目的(拾取)。光线追踪的问题在于,这个解决方案需要做很多工作才能让一个非常简单的基本功能正常工作。光线追踪也可能很慢,但如果你只有一条光线要追踪(比如手指的位置),那应该没问题。

    OpenGL 的 API 还提供了一种选择对象的技术。我建议你看看例如:http://www.lighthouse3d.com/opengl/picking/

    最后一个选项是在屏幕空间中投影对象的顶点,并使用简单的 2d 技术找出您的手指与对象的哪些面重叠。

    【讨论】:

    • ES 不提供拾取 API,但他可以通过执行渲染来执行类似的操作,每个多边形呈现​​独特的颜色,然后使用 glReadPixels 在触摸位置获取颜色,或者即使提出了一个稍微更精细但可能更有效的系统,该系统基于绘制一个非常接近的带有孔的表面,并继续使用划分的几何图形和遮挡查询(如果有记忆,iOS 5 提供了)。如果段是封闭的,那么您可以在绘制时通过将封面放在背景中并反转深度测试来进行遮挡。
    猜你喜欢
    • 2013-06-25
    • 2013-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多