Hololens 开发笔记(5)——Gaze

在前面我们粗略了解了 Hololens,包括 Hello WorldMRTKWindows Device Portal坐标系统

下面开始 Hololens 基础部分的学习,包括 GazeGesureVoiceAudio Souce 等。本篇文章来学习 Hololens 的基础开发之凝视操作。

源码地址:https://github.com/jitwxs/blog_sample

创建一个新的 Unity 项目 GazeDemo,导入 MRTK 工具包,并将项目应用为 MR 项目。

删除掉默认的相机,添加 MRTK 的 HoloLensCamera 到 Hierarchy 中。添加 MRTK 中的 CursorWithFeedback 到 Hierarchy 中。

一、凝视操作

从 MRTK 中拖拽 InputManager 到 Hierarchy 中。这是一个十分重要的 Manager,它将管理我们的凝视等输入事件。

设置 InputManager 的 SimpleSinglePointerSelector 脚本的 Cursor 属性为添加的 CursorWithFeedback。

随后添加一个 Cube 到 Hierarchy 中,来实现凝视 Cube 5 秒将其隐藏掉的效果。

新建脚本 CubeCommand,并将其添加到 Cube 上。

using UnityEngine;
using HoloToolkit.Unity.InputModule;
using System;

public class CubeCommand : MonoBehaviour, IFocusable {
    // 延迟多少秒后触发
    public double duration = 5.0;
    private DateTime? startDate;

    void Update () {
        if (startDate.HasValue)
        {
            TimeSpan span = DateTime.Now - startDate.Value;

            if (span.TotalSeconds > duration)
            {
                HideCube();
            }
        }
    }

    void HideCube()
    {
        startDate = null;
        gameObject.GetComponent<MeshRenderer>().enabled = false;
    }

    public void OnFocusEnter()
    {
        startDate = DateTime.Now;
    }

    public void OnFocusExit()
    {
        startDate = null;
        if (!gameObject.GetComponent<MeshRenderer>().enabled)
        {
            gameObject.GetComponent<MeshRenderer>().enabled = true;
        }
    }
}

运行程序,当我们将 Cursor 停留 Cube 5秒后,Cube 消失,当我们移开 Cursor 时,Cube 恢复。

总结下代码:

  1. 导包:using HoloToolkit.Unity.InputModule;
  2. 实现接口 IFocusable,当 Cursor 进入物体时,调用 OnFocusEnter() 方法,当 Cursor 移出物体时,调用 OnFocusExit() 方法。
  3. Update() 方法中计算凝视的时长,当达到 duration 时,将物体隐藏。

二、Directional indicator

假如我们为 Cube 添加了方向指示器(Directional indicator),当我们的视野中看不见该 Cube 时,方向指示器会指示出它的位置。实现步骤如下:

  1. 为 Cube 添加 MRTK 包中的 DirectionIndicator.cs 脚本。
  2. 选中该脚本,设置 Cursor 属性为 Hierarchy 中的 CursorWithFeedback;设置DirectionIndicatorObject 属性为 MRTK 包中的 HeadsUpDirectionIndicatorPointer

具体属性含义如下:

属性名含义
Cursor该物体在场景中被当作光标,方向指示器会显示在这个物体旁边
DirectionIndicatorObject方向指示器物体,该物体会一直指向附加该脚本的对象。
DirectionIndicatorColor方向指示器的颜色(方向指示器材质里的Shader必须要有“_TintColor”属性,否则颜色不会变)
VisibilitySafeFactor范围[-0.3,0.3] ,当物体在摄像机视锥的某个百分比范围中,方向指示器才会显示。(例如此值为0时,当物体完全离开摄像机视锥之后方向指示器才会显示;此值为0.1时,物体在视锥范围的90%之外,方向指示器才会显示;此值为-0.1时,物体在视锥范围的110%之外 ,方向指示器才会显示)
MetersFromCursor方向指示器从原中心到它面向方向(forward)的一个偏移值。

运行程序,你会发现一个巨大的三角箭头指示着 Cube 的方向:

MRTK 默认提供的 DirectionIndicatorObject 实在是太丑了。我这里使用 MR Input 210: Gaze Chapter 4 - Directional indicator 中提供的方向指示器,效果如下:

三、Billboarding

如果为 Cube 添加了广告牌(Billboarding)效果,他就会永远的面朝你,即使你尝试走到它的后面(应用在 Cube 上没啥意义,可以使用 Text 来测试)。

为一个 gameObject 添加广告牌效果十分简单,只要为其添加 MRTK 包下的 Billboard.cs 脚本,并设置它的 PivotAxis 属性为 Y 即可,即绕着 Y 轴实现广告牌。

四、Tag-Along

不知道你还记不记得 Hololens 的 Bloom 手势呼出主菜单的效果,主菜单是跟随你移动并且使终面朝你。这就是广告牌 + 平滑追踪的联合实现。

为要平滑追踪(Tag-Along)的物体添加 MRTK 包下的 Tagalong.cs 脚本即可。

这里我添加了一个 3D Text,并为其添加了广告牌和平滑追踪的效果,运行效果如下:

五、Cursor 底层实现

代码来源于:MR Basics 101: Complete project with device: Chapter 2 - Gaze

我们可以看下 Cursor 的效果是如何实现的,创建一个 Cursor ,它其实就是一个圆圈,为它附加脚本 WorldCursor

using UnityEngine;

public class WorldCursor : MonoBehaviour
{
    private MeshRenderer meshRenderer;

    // Use this for initialization
    void Start()
    {
        // Grab the mesh renderer that's on the same object as this script.
        meshRenderer = this.gameObject.GetComponentInChildren<MeshRenderer>();
    }

    // Update is called once per frame
    void Update()
    {
        // Do a raycast into the world based on the user's
        // head position and orientation.
        var headPosition = Camera.main.transform.position;
        var gazeDirection = Camera.main.transform.forward;

        RaycastHit hitInfo;

        if (Physics.Raycast(headPosition, gazeDirection, out hitInfo))
        {
            // If the raycast hit a hologram...
            // Display the cursor mesh.
            meshRenderer.enabled = true;

            // Move the cursor to the point where the raycast hit.
            this.transform.position = hitInfo.point;

            // Rotate the cursor to hug the surface of the hologram.
            this.transform.rotation = Quaternion.FromToRotation(Vector3.up, hitInfo.normal);
        }
        else
        {
            // If the raycast did not hit a hologram, hide the cursor mesh.
            meshRenderer.enabled = false;
        }
    }
}

Unity 是没有明确的 Gaze 的 API,在 Hololens 中,是通过射线检测来实现的。当视线接触到了碰撞物时,展示出一个⭕;当视线没有接触到碰撞物时,隐藏⭕。

(1)获取其及其子对象中的 MeshRenderer

meshRenderer = this.gameObject.GetComponentInChildren<MeshRenderer>();
  • GetComponent():获取对象中指定类型的控件(脚本)
  • GetComponentInChildren():获取对象的子对象中指定类型的控件,如果父对象中有,优先获取父对象的
  • GetComponents()、GetComponentsInChildren():返回数组

Mesh Filter(网格过滤器)用于从资源中读取网格信息(Mesh) ,读取信息之后可以传递给 Mesh Renderer(网格渲染器 ),将接受到的网格信息渲染出来。

(2)获取主相机的位置和朝向

var headPosition = Camera.main.transform.position;
var gazeDirection = Camera.main.transform.forward;

(3)调用射线检测函数,从 headPosition 射向 gazeDirection ,当碰撞到物体时,返回true,并将碰撞信息放入 hitInfo 。

Physics.Raycast(headPosition, gazeDirection, out hitInfo)

(4)如果碰撞到物体,显示 meshRenderer,并将位置移动到碰撞的位置。将⭕旋转,从(0,1,0)到碰撞点的法线。

meshRenderer.enabled = true;
this.transform.position = hitInfo.point;
this.transform.rotation = Quaternion.FromToRotation(Vector3.up, hitInfo.normal);

(5)如果没有碰撞到物体,隐藏 meshRenderer。

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值