我已在opengl为我的某个应用程序创建了一个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));
}
有人可以帮忙吗?提前谢谢!
答案 0 :(得分:5)
忘掉RayTracing和其他Top Notch算法。我们在App Store上为我们的一个应用程序(Iyan 3D)使用了一个简单的技巧。但是每次完成将场景旋转到新角度时,此技术都需要一次额外的渲染过程。以不同颜色渲染不同的对象(头部,手部,腿部等)(不是实际颜色,而是唯一颜色)。读取与屏幕位置对应的渲染图像中的颜色。您可以根据颜色找到对象。
在此方法中,您可以使用更改渲染图像分辨率来平衡准确性和性能。
答案 1 :(得分:4)
要确定物体的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。
答案 2 :(得分:2)
光线跟踪是一种选择,在许多应用程序中用于执行此操作(拾取)。光线跟踪的问题在于,此解决方案需要大量工作才能获得非常简单的基本功能。光线跟踪也可能很慢,但如果你只有一条光线要跟踪(手指的位置说),那么它应该没问题。
OpenGL的API还提供了一种拾取对象的技术。我建议您查看一下:http://www.lighthouse3d.com/opengl/picking/
最后,最后一个选项包括在屏幕空间中投影对象的顶点,并使用简单的2D技术找出手指重叠的对象的哪些面。