移动VR添加视线交互

本文介绍了如何在Unity中利用MojingSDK和Tales from the Rift实现移动VR的视线交互功能。首先创建视线点(Crosshair),设置canvas和image参数,并用一圈红线表示选中物体的过程。接着,为EventSystem添加特定脚本并移除默认模块,同时为Image添加Gaze Fuze脚本。最后,给Main Camera添加Physics Raycaster组件以完成交互控制。

使用MojingSDK+tales from the rift。


1.制作视线点

Crosshair为quad文件,参数如下图:

canvas 和image的参数分别如下:

image中加入的图片为一圈红线,当实现注视物体时,这一圈线会围绕crosshair进行旋转,代表选中物体的一个过程。

2.接下来是添加响应和控制脚本

给eventsystem添加如下脚本:

注意取消其自带的standalone module模块。


给image添加gaze fuze脚本。

3.给main camera 添加physics raycaster组件。

《附录》gaze fuze代码如下:

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class GazeFuse : MonoBehaviour 
{
    public GameObject gazeGameObject;
    private Image image;

    void Start() 
    {
        image = GetComponent<Image>();
    }
    
    void Update() 
    {
        if (gazeGameObject == null || GazeInputModule2.gazeGameObject == gazeGameObject) 
        {
            FuseAmountChanged(GazeInputModule2.gazeFraction);
        }
    }

    void FuseAmountChanged(float fuseAmount)
    {
        if (image != null)
        {
            image.fillAmount = fuseAmount;
        }
    }

}


Gaze input module 2代码如下:

// Gaze Input Module by Peter Koch <peterept@gmail.com>
using UnityEngine;
using UnityEngine.EventSystems;
using System.Collections.Generic;

// To use:
// 1. Drag onto your EventSystem game object.
// 2. Disable any other Input Modules (eg: StandaloneInputModule & TouchInputModule) as they will fight over selections.
// 3. Make sure your Canvas is in world space and has a GraphicRaycaster (should by default).
// 4. If you have multiple cameras then make sure to drag your VR (center eye) camera into the canvas.
public class GazeInputModule2 : PointerInputModule 
{
    public enum Mode { Click = 0, Gaze };
    public Mode mode;

    [Header("Click Settings")]
    public string ClickInputName = "Submit";
    [Header("Gaze Settings")]
    public float GazeTimeInSeconds = 2f;

    // Current gazed at object and gaze time progress
    public static float gazeFraction { get; private set; } 
    public static GameObject gazeGameObject { get; private set; } 

    public RaycastResult CurrentRaycast;

    private PointerEventData pointerEventData;
    private GameObject currentLookAtHandler;
    private float currentLookAtHandlerClickTime;

    public override void Process()
    { 
        HandleLook();
        HandleSelection();
    }

    void HandleLook()
    {
        if (pointerEventData == null)
        {
            pointerEventData = new PointerEventData(eventSystem);
        }
        // fake a pointer always being at the center of the screen
        pointerEventData.position = new Vector2(Screen.width/2, Screen.height/2);
        pointerEventData.delta = Vector2.zero;
        List<RaycastResult> raycastResults = new List<RaycastResult>();
        eventSystem.RaycastAll(pointerEventData, raycastResults);
        CurrentRaycast = pointerEventData.pointerCurrentRaycast = FindFirstRaycast(raycastResults);
        ProcessMove(pointerEventData);
    }
    
    void HandleSelection()
    {
        gazeFraction = 0; 
        if (pointerEventData.pointerEnter != null)
        {
            // if the ui receiver has changed, reset the gaze delay timer
            GameObject handler = ExecuteEvents.GetEventHandler<IPointerClickHandler>(pointerEventData.pointerEnter);
            if (currentLookAtHandler != handler)
            {
                gazeGameObject = currentLookAtHandler = handler;

                currentLookAtHandlerClickTime = Time.realtimeSinceStartup + GazeTimeInSeconds;
            }

            if (mode == Mode.Gaze && currentLookAtHandler != null)   // added for progressCursor
                gazeFraction = Mathf.Clamp01 (1 - (currentLookAtHandlerClickTime - Time.realtimeSinceStartup) / GazeTimeInSeconds);   // added for progressCursor
            
            // if we have a handler and it's time to click, do it now
            if (currentLookAtHandler != null && 
                (mode == Mode.Gaze && Time.realtimeSinceStartup > currentLookAtHandlerClickTime) || 
                (mode == Mode.Click && Input.GetButtonDown(ClickInputName)))
            {
                if (EventSystem.current.currentSelectedGameObject != null)
                {
        //            ExecuteEvents.ExecuteHierarchy(EventSystem.current.currentSelectedGameObject, pointerEventData, ExecuteEvents.deselectHandler);
                }

                EventSystem.current.SetSelectedGameObject(currentLookAtHandler);
                gazeFraction = 0;   // added for progressCursor

                ExecuteEvents.ExecuteHierarchy(currentLookAtHandler, pointerEventData, ExecuteEvents.pointerClickHandler);
                currentLookAtHandlerClickTime = float.MaxValue;
                            ExecuteEvents.ExecuteHierarchy(EventSystem.current.currentSelectedGameObject, pointerEventData, ExecuteEvents.deselectHandler);
            }
        }
        else
        {
            gazeGameObject = currentLookAtHandler = null;
        }
    }


}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值