Hololens开发笔记之Gaze凝视射线
凝视是HoloLens首要输入方式,形式功能类似于桌面系统的光标,用于选择操作全息对象。然而在Unity中并没有明确的Gaze API或者组件。
概念上来说,Gaze是通过用户头部两眼之间发出一条向前方的射线来实现的,射线可以识别它所碰撞的物体。在Unity中,使用Main Camera来表示用户头部的位置和朝向。准确的说,是指UnityEngine.Camera.main.transform.forward 和 UnityEngine.Camera.main.transform.position.调用Physics.RayCast 发出射线后可以得到RaycastHit结果,该结果包含了碰撞点的3D位置参数和碰撞对象。
实现Gaze的例子
void Update()
{
RaycastHit hitInfo;
if (Physics.Raycast(
Camera.main.transform.position,
Camera.main.transform.forward,
out hitInfo,
20.0f,
Physics.DefaultRaycastLayers))
{
// 如果射线成功击中物体
// hitInfo.point代表了射线碰撞的位置
// hitInfo.collider.gameObject代表了射线注视的全息对象
}
}
在使用Gaze的时候,尽量避免每个物体都发出凝视射线,而是使用单例对象来管理凝视射线和其结果。
可视化凝视的具体例子
可以直接使用HoloToolkit中的GazeManager.cs脚本来实现凝视射线。
可以参考或直接使用HoloToolkit-Unity项目中的GazeManager.cs和预制的各种指针资源,包括Cursor.prefab 和 CursorWithFeedback.prefab 等。
1、添加GazeManager.cs
点击“ Create Empty” 创建一个空游戏对象,并将其命名为 Manager,为 Manager对象添加核心脚本组件GazeManager.cs
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information. using UnityEngine;
using UnityEngine.VR.WSA; namespace HoloToolkit.Unity
{
/// <summary>
/// GazeManager determines the location of the user's gaze, hit position and normals.
/// </summary>
public partial class GazeManager : Singleton<GazeManager>
{
[Tooltip("Maximum gaze distance, in meters, for calculating a hit.")]
public float MaxGazeDistance = 15.0f; [Tooltip("Select the layers raycast should target.")]
public LayerMask RaycastLayerMask = Physics.DefaultRaycastLayers; /// <summary>
/// Physics.Raycast result is true if it hits a hologram.
/// </summary>
public bool Hit { get; private set; } /// <summary>
/// HitInfo property gives access
/// to RaycastHit public members.
/// </summary>
public RaycastHit HitInfo { get; private set; } /// <summary>
/// Position of the intersection of the user's gaze and the holograms in the scene.
/// </summary>
public Vector3 Position { get; private set; } /// <summary>
/// RaycastHit Normal direction.
/// </summary>
public Vector3 Normal { get; private set; } /// <summary>
/// Object currently being focused on.
/// </summary>
public GameObject FocusedObject { get; private set; } [Tooltip("Checking enables SetFocusPointForFrame to set the stabilization plane.")]
public bool SetStabilizationPlane = true;
[Tooltip("Lerp speed when moving focus point closer.")]
public float LerpStabilizationPlanePowerCloser = 4.0f;
[Tooltip("Lerp speed when moving focus point farther away.")]
public float LerpStabilizationPlanePowerFarther = 7.0f; private Vector3 gazeOrigin;
private Vector3 gazeDirection;
private float lastHitDistance = 15.0f; private void Update()
{
gazeOrigin = Camera.main.transform.position;
gazeDirection = Camera.main.transform.forward; UpdateRaycast();
UpdateStabilizationPlane();
} /// <summary>
/// Calculates the Raycast hit position and normal.
/// </summary>
private void UpdateRaycast()
{
// Get the raycast hit information from Unity's physics system.
RaycastHit hitInfo;
Hit = Physics.Raycast(gazeOrigin,
gazeDirection,
out hitInfo,
MaxGazeDistance,
RaycastLayerMask); GameObject oldFocusedObject = FocusedObject;
// Update the HitInfo property so other classes can use this hit information.
HitInfo = hitInfo; if (Hit)
{
// If the raycast hits a hologram, set the position and normal to match the intersection point.
Position = hitInfo.point;
Normal = hitInfo.normal;
lastHitDistance = hitInfo.distance;
FocusedObject = hitInfo.collider.gameObject;
}
else
{
// If the raycast does not hit a hologram, default the position to last hit distance in front of the user,
// and the normal to face the user.
Position = gazeOrigin + (gazeDirection * lastHitDistance);
Normal = -gazeDirection;
FocusedObject = null;
} // Check if the currently hit object has changed
if (oldFocusedObject != FocusedObject)
{
if (oldFocusedObject != null)
{
oldFocusedObject.SendMessage("OnGazeLeave", SendMessageOptions.DontRequireReceiver);
}
if (FocusedObject != null)
{
FocusedObject.SendMessage("OnGazeEnter", SendMessageOptions.DontRequireReceiver);
}
}
} /// <summary>
/// Adds the stabilization plane modifier if it's enabled and if it doesn't exist yet.
/// </summary>
private void UpdateStabilizationPlane()
{
// We want to use the stabilization logic.
if (SetStabilizationPlane)
{
// Check if it exists in the scene.
if (StabilizationPlaneModifier.Instance == null)
{
// If not, add it to us.
gameObject.AddComponent<StabilizationPlaneModifier>();
}
} if (StabilizationPlaneModifier.Instance)
{
StabilizationPlaneModifier.Instance.SetStabilizationPlane = SetStabilizationPlane;
}
}
}
}
2、创建一个新的游戏对象Cube,用来测试凝视效果
3、添加Cursor
就像PC使用鼠标来选中和交互图标一样,你可以为凝视也实现一个指针来更好的代表用户的凝视。
从 HoloToolkit/Input/Prefabs/ 目录下拖拽 Cursor Prefab 组件到场景中。这样当凝视在全息对象时,其表面会出现一个蓝色的光圈,表示当前凝视该对象,当射线离开该游戏对象时,Cursor变成一个点光源,以此来区分是否凝视游戏对象。
可以查看到Cursor中存在两个光标对象,分别是凝视在对象上及离开光息对象时分别显示的光标

CursorManager.cs
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information. using HoloToolkit.Unity;
using UnityEngine; /// <summary>
/// CursorManager class takes Cursor GameObjects.
/// One that is on Holograms and another off Holograms.
/// 1. Shows the appropriate Cursor when a Hologram is hit.
/// 2. Places the appropriate Cursor at the hit position.
/// 3. Matches the Cursor normal to the hit surface.
/// </summary>
public partial class CursorManager : Singleton<CursorManager>
{
//凝视射线在全息对象上时显示的光标对象
[Tooltip("Drag the Cursor object to show when it hits a hologram.")]
public GameObject CursorOnHolograms;
//凝视射线离开全息对象时显示的光标对象
[Tooltip("Drag the Cursor object to show when it does not hit a hologram.")]
public GameObject CursorOffHolograms; [Tooltip("Distance, in meters, to offset the cursor from the collision point.")]
public float DistanceFromCollision = 0.01f; void Awake()
{
//当未设定光标对象时直接返回
if (CursorOnHolograms == null || CursorOffHolograms == null)
{
return;
} // Hide the Cursors to begin with.
CursorOnHolograms.SetActive(false);
CursorOffHolograms.SetActive(false);
} void LateUpdate()
{
if (GazeManager.Instance == null || CursorOnHolograms == null || CursorOffHolograms == null)
{
return;
}
//当凝视射线在全息对象上及离开全息对象时,分别显示不同的光标对象,以此来进行区分
if (GazeManager.Instance.Hit)
{
CursorOnHolograms.SetActive(true);
CursorOffHolograms.SetActive(false);
}
else
{
CursorOffHolograms.SetActive(true);
CursorOnHolograms.SetActive(false);
} //计算并安置光标
// Place the cursor at the calculated position.
this.gameObject.transform.position = GazeManager.Instance.Position + GazeManager.Instance.Normal * DistanceFromCollision; // Orient the cursor to match the surface being gazed at.
gameObject.transform.up = GazeManager.Instance.Normal;
}
}
4、运行测试
当凝视射线在Cube上时,出现蓝色的光圈,表示当前凝视的点在该位置

当凝视射线离开Cube时,光标显示为一个点光源

Hololens开发笔记之Gaze凝视射线的更多相关文章
- HoloLens开发手记 - Unity之Gaze凝视射线
凝视是HoloLens首要输入方式,形式功能类似于桌面系统的光标,用于选择操作全息对象.然而在Unity中并没有明确的Gaze API或者组件. 实现Gaze Implementing Gaze 概念 ...
- Hololens开发笔记之使用Unity开发一个简单的应用
一.Hololens概述 Hololens有以下特性 1.空间映射借助微软特殊定制的全息处理单元(HPU),HoloLens 实现了对周边环境的快速扫描和空间匹配.这保证了 HoloLens能够准确地 ...
- Hololens开发笔记之Gesture手势识别(Manipulation手势控制物体旋转)
Manipulation gesture:保持点击手势,在3D世界中绝对运动 当你想要全息图像1:1响应用户手部移动时,操纵手势能被用于移动.缩放或旋转全息图像.如此的一个用处是使得用户可以在世界中绘 ...
- Hololens开发笔记之Gesture手势识别(Manipulation手势控制物体平移)
Manipulation gesture:保持点击手势,在3D世界中绝对运动 当你想要全息图像1:1响应用户手部移动时,操纵手势能被用于移动.缩放或旋转全息图像.如此的一个用处是使得用户可以在世界中绘 ...
- Hololens开发笔记之Gesture手势识别(手势检测反馈)
本文实现当使用者手出现在Hololens视野范围内时,跟踪手并给出反馈的效果. 1.在Manager上添加HandsManager脚本组件,用于追踪识别手 HandsManager.cs如下(直接使用 ...
- Hololens开发笔记之Gesture手势识别(基本介绍)
手势识别是HoloLens交互的重要输入方法之一.HoloLens提供了底层API和高层API,可以满足不同的手势定制需求.底层API能够获取手的位置和速度信息,高层API则借助手势识别器来识别预设的 ...
- Hololens开发笔记之连接PC实现资源共享
官网原文介绍:https://developer.microsoft.com/en-us/windows/holographic/using_the_windows_device_portal Hol ...
- HoloLens开发笔记之Gesture input手势输入
手势是HoloLens三个首要输入形式之一.一旦你使用凝视定位了一个全息图像,手势允许你与它交互.手势输入允许你使用手或者点击器原生地与全息图像交互. 手势之外,你也可以在应用中使用语音输入来交互. ...
- Hololens开发笔记之Gesture手势识别(单击,双击)
本文使用手势识别实现识别单击及双击手势的功能,当单击Cube时改变颜色为蓝色,当双击Cube时改变颜色为绿色. 手势识别是HoloLens交互的重要输入方法之一.HoloLens提供了底层API和高层 ...
随机推荐
- 安卓应用运营知识:VersionCode和VersionName
本文转载于:http://blog.sina.com.cn/s/blog_580a227a0101bdzb.html 小米应用商店运营了大概半年了,过程中有喜有泪,我们在运营过程中,发现有的运营和商务 ...
- (转) A Survival Guide to a PhD
A Survival Guide to a PhD Sep 7, 2016 This guide is patterned after my “Doing well in your courses”, ...
- windows的页自映射机制
windows下由于启用了页机制,所有软件层面的地址操作都是VA,通过descriptor(base address(32bit))+offset得到的线性地址并不直接对应物理地址,而是经过页转换机构 ...
- SQLite在多线程环境下的应用
文一 SQLite的FAQ里面已经专门说明,先贴出来.供以后像我目前的入门者学习. (7) 多个应用程序或者同一个应用程序的多个例程能同时存取同一个数据库文件吗? 多进程可以同时打开同一个数据库,也可 ...
- DYNAMIC_DOWNCAST、STATIC_DOWNCAST、CRuntimeClass和IsKindOf
DYNAMIC_DOWNCAST.STATIC_DOWNCAST.CRuntimeClass和IsKindOf DYNAMIC_DOWNCAST(class, pointer ):如果pointe ...
- 从开发的角度比较 ASP.NET Web 服务与 WCF
Windows Communication Foundation (WCF) 具有一个 ASP.NET 兼容模式选项,用户使用此选项可以对 WCF 应用程序进行编程和配置,使其像 ASP.NET We ...
- Debug目录、Release目录,bin目录、obj目录,vshost.exe.config文件、.exe.config文件分析【C#】
原文地址:http://blog.csdn.net/itwit/article/details/6803338 今天写程序的时候,需要更改.exe.config文件中的引用的webservice地址, ...
- 在同步中调用异步方法[.net 4.5]
using System; using System.Threading; using System.Threading.Tasks; namespace Microsoft.AspNet.Ident ...
- 【转载】onclick与onCommand的区别
这两个事件没有本质区别,都是点击执行一个事件.不同在于传递的参数不一 样,OnClick (object sender, EventArgs e),OnCommand (object sender, ...
- 【转】JS跨域(ajax跨域、iframe跨域)解决方法及原理详解(jsonp)
这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被 ...