leap motion怎么对应屏幕上的位置

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leap motion怎么对应屏幕上的位置相关的知识,希望对你有一定的参考价值。

leap motion获得的坐标是三维世界的坐标感觉,怎么对应在屏幕上相应位置绘制模型啊?

概述
屏幕类提供了一个在参照Leap Motion帧中显示屏的坐标和朝向。函数Screen::intersect()计算手指或工具指向方向射线与屏幕平面的交点的位置。此外,Screen::project()函数计算某点投影到屏幕平面的位置。

在使用Screen类之前,考虑到注册屏幕位置会需要你花一些精力,并且只有当你移动屏幕或者Leap才是有效的。你的应用对于API的使用必须是充分值得的,这样用户才会觉得他们的努力没有白费。我们建议你,让你的用户清楚了解为什么你需要他们去注册他们屏幕的位置,并且为用户提供一个快速的测试以验证屏幕位置是否依旧准确。

使用屏幕定位功能的说明可以参考Screen location.
屏幕坐标
对于每个已知屏幕,屏幕类提供了一个原点和向量以表示屏幕范围水平和垂直方向。一个正交的向量也会有提供。

上图:原点和已定位屏幕的方向向量

屏幕的原点坐落在下方,屏幕的左手角落。坐标向量与屏幕一边平行。向量的长度表示以毫米为单位的屏幕长度。正交向量是一个单位朝向向量与屏幕表面正交。
交点和投影点
屏幕类提供了一个intersect()方法来计算手指或者工具指向屏幕的交点。这个函数从尖端物体发射一个射线,然后判断射线与屏幕平面在哪里相交。只要尖端物体指向屏幕所处位置,就会返回一个有效的数值。如果交点是平行的或者指向方向不在屏幕上,在交叉向量中的坐标则都为NaN(not-a-number)。

屏幕类还提供了一个近似的intersect()函数,接受位置和朝向向量,并且计算它与屏幕交点,这样就不需要一个尖端物体了。

上图:三个指向以及与之对应的交叉点
@指针A与屏幕平面相交于屏幕外侧。
@指针B与屏幕直接相交。
@指针C没有与屏幕相交。[是平行的]

另外,屏幕类提供了一个project()函数来计算点在屏幕上的投影位置。与intersect()函数不同的是,project()函数永远返回一个有效值,因为点永远可以投影到平面上。

上图:2个点与相对于的投影点
@点A直接投影到屏幕上。
@点B投影到了屏幕外侧。

你可以依据Leap Motion坐标系统不断调用得到交点和投影点。返回的坐标是三维向量,以Leap Motion为原点毫米为单位衡量的点坐标。
依次的,你可以请求二维归一化的坐标,它们把交点和投影点定义成相对于屏幕低端左下角并且在屏幕平面内的坐标。

当使用归一化坐标时,原点是(0,0,0),相反的右上角坐标为(1,1,0)。这些点在屏幕平面以内,并且它们的x和y数值在0到1之间,表示点距离屏幕两边的比率(当使用归一化坐标时,z坐标的值一直是0)。例如,在屏幕中心的点被归一为(0.5,0.5,0)。对于交点和投影点,归一化的坐标在屏幕边界外时可能小于0也可能大于1。

默认时,intersect()和project()函数将坐标归一化到(clamp夹在这个范围里)坐标范围(0~1,0~1,0)。这意味着,任何在屏幕边框外的交点和投影点实际上被移动到边框上。但调用intersect()或者project()函数时,你可以通过设置clapRatio参数,来修改默认的“夹板区域”。默认的夹板率是1.0。使用一个更小的数可以减小夹板区域,而使用一个大的数值可以增大区域。例如将clampRatio设置为0.5会将交互区域缩小为以屏幕为中心50%区域,并且把说有点的坐标压缩在0.25到0.75范围里。同样的,如果把clampRatio设置为2.0会将交互区域扩大1倍,点的坐标扩展到-0.5到1.5之间[这二个功能很实用啊,这样可以限定交互区域范围,减少开发难度]。无论怎么设置,交互区域永远是以屏幕为中心的[一般都是盯着屏幕操作的(主要是能直接看到操作反馈结果),他们这样设计理所当然]。
找到最近的屏幕
你可以通过控制器实例对象的注册位置得到一张所有屏幕的列表:
Controller controller;
ScreenList screens = controller.calibratedScreens();

注意,屏幕列表永远至少包含一项,即使用户从未注册过屏幕的位置。这项代表用户默认的屏幕。

你可以获取从手指或工具引出的射线会与屏幕列表对象相交的,最近的屏幕[如果有好多屏幕也只会得到最近的那个]:
Controller controller;
Frame frame = controller.frame();
if (frame.pointables().count() > 0)
Pointable pointable = frame.pointables()[0];
ScreenList screens = controller.calibratedScreens();
Screen screen = screens.closestScreenHit(pointable);

同样地,你还可以在屏幕列表对象中,通过一个点(诸如指尖或者工具的末端位置)来得到与之最靠近的屏幕。[注意就最后一行不一样,函数和传入参数都不一样]
Controller controller;
Frame frame = controller.frame();
if (frame.pointables().count() > 0)
Pointable pointable = frame.pointables()[0];
ScreenList screens = controller.calibratedScreens();
Screen screen = screens.closestScreen(pointable.tipPosition());

找到交点的像素坐标

Controller controller;
Frame frame = controller.frame();
if (frame.pointables().count() > 0)
Pointable pointable = frame.pointables()[0];
ScreenList screens = controller.calibratedScreens();
Screen screen = screens.closestScreenHit(pointable);

Vector normalizedCoordinates = screen.intersect(pointable, true);
int xPixel = (int)(normalizedCoordinates.x * screen.widthPixels());
int yPixel = screen.heightPixels() - (int)(normalizedCoordinates.y * screen.heightPixels());

找到在Leap Motion坐标系下的交点坐标
你可以使用intersect()函数得到归一化的坐标,以帮你计算在屏幕上的某一个交点的像素点坐标[这个很必要!]。
Controller controller;
Frame frame = controller.frame();
if (frame.pointables().count() > 0)
Pointable pointable = frame.pointables()[0];
ScreenList screens = controller.calibratedScreens();
Screen screen = screens.closestScreenHit(pointable);

Vector normalizedCoordinates = screen.intersect(pointable, true);
int xPixel = (int)(normalizedCoordinates.x * screen.widthPixels());
int yPixel = screen.heightPixels() - (int)(normalizedCoordinates.y * screen.heightPixels());

设置交互区域的大小
当使用归一化坐标时,通过调用inersect()函数来设置calmpRatio参数,你可以将用户说指向的交互区域扩大或缩小。默认情况下,clampRatio参数为1.0,与屏幕边缘相匹配[自适应很好很强大]。返回任何在屏幕边界外交点的坐标时,它们都会被归一到边界上。(在交互区域内的点不会受到归一影响)

为了将交互区域二等分,在你调用intersect()函数时,可以将clampRatio参数设置为0.5。
Vector normalizedCoordinates = screen.intersect(pointable, true, 0.5);
如果需要把区域扩展一倍,可以将clampRatio也乘以2。
Vector normalizedCoordinates = screen.intersect(pointable, true, 2.0);
找到指向某处的手指或工具与屏幕的距离
为了取得手指或者工具的指向与屏幕交点的坐标,可以简单地将2个表示这些点的向量相减再取模就可以得到结果[中学几何知识]。当调用函数intersect()来获取交点,可以将归一化参数设置为false。
Controller controller;
Frame frame = controller.frame();
if (frame.pointables().count() > 0)
Pointable pointable = frame.pointables()[0];
ScreenList screens = controller.calibratedScreens();
Screen screen = screens.closestScreenHit(pointable);

Vector intersection = screen.intersect(pointable, false);
Vector tipToScreen = intersection - pointable.tipPosition();
float pointingDistance = tipToScreen.magnitude();


为了得到手指、工具与屏幕平面最近的距离,也就是从尖端末梢的点做垂线到屏幕的那个距离,可以使用distanceToPoint()函数传入尖端坐标。
Controller controller;
Frame frame = controller.frame();
if (frame.pointables().count() > 0)
Pointable pointable = frame.pointables()[0];
ScreenList screens = controller.calibratedScreens();
Screen screen = screens.closestScreenHit(pointable);

float perpendicularDistance = screen.distanceToPoint(pointable.tipPosition());
追问

这篇博客我看过,但是没怎么懂,请教一下,注册屏幕是什么意思呀?
我就是opengl连了leap motion,想在对应位置绘制模型。

参考技术A 型号应该7007.型号屏幕物料参考价:380

基于unity3D游戏引擎与leap motion体感控制器的体感音乐交互类游戏

参考技术A 体感音乐游戏融合了音乐,运动和游戏元素,使游戏玩家获得多种感官体验,受到

游戏玩家特别是年轻玩家的青睐。本文利用 unity3D 游戏引擎配合 leap motion 体感控

制设备实现了一种体感音乐交互游戏。主要使用了手势检测、节奏分析、碰撞检测等关

键技术实现游戏模式选择模块,音乐选择模块,游戏模块与分数结算模块。设计的游戏

利用 leap motion 体感控制设备将体感音乐融入到游戏环境中,游戏玩家可以通过手势

或键盘操纵游戏过程。由于加入体感控制设计,使游戏模式更加丰富,增强了游戏的可

玩性与玩家的活动范围。改变了传统的游戏模式,使得游戏过程更加灵活,更利于玩家

的身心健康。使用 DOTween 游戏动画引擎在游戏中添加的补帧动画效果使游戏界面更

加灵活,大大提升了玩家体验感。最后对实现的游戏进行了测试。

关键词 人机交互  Leap Motion 控制器  Unity3D  体感游戏  节奏分析

1.选择游戏模式

玩家进入游戏后,将会观看游戏进入指南与操作手势帮助(如图17、18所示),之后无需玩家操作,经过一段时间后自动进入模式选择场景。

玩家在此处可选择将手左滑锁定本地歌曲模式,这时可以看到写有“custom music”的游戏对象面积小幅度变大,而玩家将手右滑锁定内置歌曲模式时,可以看到写有“select music”的游戏对象面积以同等程度变大。

之后玩家握拳选定模式,这时被选中的模式相对应的游戏对象面积进一步增大,之后整个游戏场景逐渐消失黑屏数秒后进入相应的歌曲挑选场景,值得注意的是在场景黑屏之前取消握拳动作意味着玩家放弃选定,游戏对象的大小会恢复并等待玩家的下一次操作。

2.选择游戏歌曲

2.1本地模式

通过选定写有“custom music”的游戏对象进入本地歌曲挑选界面,玩家可以通过屏幕中显示的虚拟手型确定自己手部相对屏幕所处的位置 ,此时对于屏幕中所显示的歌曲对象,可以做出点击手势点击“listen”按钮试听音乐,点击“play”按钮开始所选择歌曲的游戏。

此时若界面中罗列了超出屏幕显示数量的歌曲,玩家可以通过手的上下滑动浏览歌曲列表。

2.2内置模式

通过选定写有“select music”的游戏对象进入内置歌曲挑选界面,玩家可以通过屏幕中显示的虚拟手型确定自己的手势动作,通过手的左右挥动来选择不同的歌曲,锁定歌曲后,玩家可以通过将手掌反转180°的操作来更换歌曲游戏的难易度,每翻转一次玩家都可以通过屏幕中的难易度栏来确认目前的游戏难易度,锁定难易度后,玩家通过握拳操作选定当前歌曲并且以此歌曲开始游戏,此时可以观察到屏幕中显示歌曲封面的对象面积逐渐增大,之后场景透明度降低,在数秒的黑屏缓冲后进入游戏场景。

值得注意的是,如果在场景进入黑屏之前取消握拳手势,则被认定为放弃进入游戏,屏幕中的封面游戏对象会逐渐恢复此前大小并等待玩家的下一次操作。

3.进入游戏

玩家进入游戏后可以看到以宇宙为背景的游戏场景,跟随音乐的节奏会在屏幕中出现蓝色节奏点,节奏点在运动至与屏幕下方的两个光球相同的z坐标位置时,玩家需要操纵两个光球,使其与节奏点x坐标重合,也就是所谓的“接住”节奏点。玩家“接住”节奏点时,屏幕上出现hit字样并增加玩家的生命值(如图23所示),当玩家错过某个节奏点时,屏幕上出现miss字样并减少玩家的生命值(如图24所示)。若玩家连续“接住”节奏点且没有任何一个点被错过时,玩家的连击数会根据“接住”的节奏点数量增加,一旦玩家错过了某一个节奏点,则连击数立即归零。

玩家通过手的左右滑动来操纵光球,光球时刻保持与玩家手所在位置相同的x坐标,而除此之外的y,z则保持游戏默认值不变,在游戏开始时玩家若判断音乐前奏过长影响游戏体验,可以通过握拳的手势跳过音乐前奏部分。在游戏进行的任何时间玩家都能够使用将手掌反转180°的方式更改游戏背景的颜色以享受更加舒适的游戏过程。

4.游戏结束

(1)显示游戏成绩

在歌曲结束后,游戏界面在数秒的黑屏缓冲后进入游戏分数结算场景,场景中会显示玩家当前游戏的得分与失分,也就是“接住”与错过的节奏点的数量,此外还会显示玩家的连击数与游戏等级,以此来判断本局游戏玩家的表现是否出色。

(2)选择下一步动作

此时屏幕右下方存在两个游戏对象分别写有“retry”与“back”字样,玩家通过手的左右挥动来做出不同的选择,被选择的游戏对象面积将会增大,锁定选择后玩家通过握拳动作进入相应的下一个场景,选择“retry”对象时,玩家将再次体验与上一局游戏相同的歌曲与难易度,选择“back”对象时,玩家将会回到相应的音乐挑选场景,从本地音乐模式进入时玩家回到本地音乐挑选场景,从内置音乐模式进入时玩家回到内置音乐挑选场景。

以上是关于leap motion怎么对应屏幕上的位置的主要内容,如果未能解决你的问题,请参考以下文章

HTC Vive 与Leap Motion 出现位置错误的问题

如何在 Leap Motion 上检测用于相机校准的棋盘?

Unity UGUI怎么样获得UI在屏幕上的位置坐标?

Unity UGUI怎么样获得UI在屏幕上的位置坐标

如何利用Leap Motion创建支持手势操控的Web游戏

leap motion是啥意思?