LoginSignup
0
1

More than 3 years have passed since last update.

【用Unity开发Oculus Quest用的APP】用Hand tracking功能抓住物体

Posted at

◆ 写在开头

上一回、写了关于Oculus Quest 中Hand tracking功能的使用的内容。
所以这次的内容上,关于如何使用Hand tracking实现抓住物体的方法。

关于手的动作、手指状态的取得等,这里就不详细写了。
具体方法等,请自行查询。

如果制作中用什么问题或不明点,
有需要的话可以参考下面两条内容。
用Unity开发Oculus Quest用的APP 导入APP、进行运行状态确认
抓住物体吧(物体的设置与制作)
Hand tracking功能的使用

关于这次的内容,抓住物体的实行方法
完全属于自己想当然的做法,参考性比较低……请谅解。

◆ 开发环境

macOS Mojave 版本 10.14.6
Unity 2018.4.12f1
Android SDK
为了能够使用Hand tracking的功能,
Oculus的版本必须得是(Ver12)或以上。(需要更新的请即时更新)

◆ 制作顺序

  • 准备阶段的说明
  • 实现【抓住】功能
  • 手指动作的判断
  • 理论关系和代码
  • 动作确认

准备阶段的说明

スクリーンショット 2020-02-17 18.43.04.png
首先准备必要的Object,
在这里我们意见实装了Hand tracking功能、准备好了自带物理的几个测试用方块。
方块的尺寸颜色等请自由设置(方便看清就行)。

为了更直观的显示代码部分是否有正确实行等、
这里制作了观测用Canvas,当然这个只是起到了方便看的作用并不是必须要制作的东西,
只是单纯的有了会更直观而已。
当然桌子也不是必须品。

实现【抓住】功能

以前在抓住物体吧(物体的设置与制作)中,只要成功的在画面中表示手,便可以直接实行抓取,
但Hand tracking好像没有办法直接抓取的样子。
02.png
所以,
这次要做的事情就是,
当手触碰到物体且作出了抓住物体的动作时,把被触碰物体放入手的Object中,
也就是说,成为手的子级。

当然,除了成为子级以外,
当发生抓住判定时,被抓物体跟随手一起移动也是实现的方法之一。

手指动作的判断

ovrHand.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ovrHand : MonoBehaviour
{
    private OVRHand _ovrHand;
    // 抓住状态的取得
    public bool _catching;

    // Start is called before the first frame update
    void Start()
    {
        _catching = false;
        _ovrHand = this.gameObject.GetComponent<OVRHand>();
    }
    // Update is called once per frame
    void Update()
    {
        if (_ovrHand.GetFingerIsPinching(OVRHand.HandFinger.Index))
        {
            _catching = true;
        }
        else
        {
            _catching = false;
        }
    }
}

将上述内容直接拖入「OVRHandPrefab」中。
关于手动作的取得、变数「_ catching」的制作与「_ catching」的说明,之后再说。

GetFingerIsPinching可以判断手指尖是否接触
OVRHand.HandFinger可以判断某手指是否与大拇指接触,这次接触手指的设置是食指。
当食指尖与大拇指触碰时,「_catching」变为true。

将「_catching」的状态在Canvas上表示
(和上面讲到的一样Canvas并不是必需品,下面的内容里讲省略全部关于Canvas的内容)

理论关系和代码

cubeTouch.cs
    private ovrHand _ovrHand;
    private bool _touchIN;      //触碰
    private bool _catch;        //抓住动作
    private bool _hold;         //是否能抓住

    // Start is called before the first frame update
    void Start()
    {
        _ovrHand = FindObjectOfType<ovrHand>();
    }
void Update()
    {
        // 取得手的动作 判断是否抓住
        _catch = _ovrHand._catching;
        touchCube();
        CatchCube();
    }
void touchCube()
    {
        if (_touchIN == true && _catch == false)
        {
            _hold = true;
        }
    }

    void CatchCube()
    {
        if (_hold == true && _catch == true)
        {
            _touchIN = false;
        }
        else if (_touchIN = false && _touchIN == false)
        {
            _hold = false;
        }
    }

首先,需要分析关于抓住物体这一动作。

当手是抓住动作状态的时候触碰物体,是不能抓住物体的。
而在手触碰物体后,实行抓住动作便可抓住物体。

将上述内容用代码表示。

cubeTouch.cs
void OnCollisionStay(Collision other)
    {
        if (other.gameObject.name == "Hand_Index3_CapsuleRigidBody" ||
            other.gameObject.name == "Hand_Index2_CapsuleRigidBody" ||
            other.gameObject.name == "Hand_Thumb3_CapsuleRigidBody" ||
            other.gameObject.name == "Hand_Thumb2_CapsuleRigidBody" 
            )
        {
            _touchIN = true;
            // 固定位置且消除物理す
            gameObject.GetComponent<Rigidbody>().constraints = RigidbodyConstraints.FreezeAll;
            gameObject.GetComponent<Rigidbody>().isKinematic = true;
        }
    }

参考上述内容,
想要实行抓住动作,首先需要从触碰物体开始。

关于手指各个部位的名字请参考最上面的连接。
发生触碰时,「 _touchIN」的状态变为true。

cubeTouch.cs
void CatchCube()
    {
        if (_hold == true && _catch == true)
        {
            // 变为右手子级
            gameObject.transform.SetParent(_rightHandAnchor.gameObject.transform);
            // 消除重力与触碰判定
            gameObject.GetComponent<Rigidbody>().useGravity = false;
            gameObject.GetComponent<BoxCollider>().isTrigger = true;
            _touchIN = false;
        }
        else if (_touchIN = false && _touchIN == false)
        {
            // 解除父级关系
            gameObject.transform.parent = null;
            // 恢复重力 触碰
            gameObject.GetComponent<Rigidbody>().useGravity = true;
            gameObject.GetComponent<BoxCollider>().isTrigger = false;
            // 恢复位置移动与物理
            gameObject.GetComponent<Rigidbody>().constraints = RigidbodyConstraints.None;
            gameObject.GetComponent<Rigidbody>().isKinematic = false;
            _hold = false;
        }
    }

这次准备的方块中因为加入了物理效果,所以当发生抓住判定时,需要将其去掉。
(没放入物理的情况下就没有写的必要了)
请根据自己的状况判断后,将必要的内容写入「CatchCube()」中。
(代码的意思,在上面有写请参考)

最后,把「cubeTouch.cs」拖入到方块中,完成必要的设置就算完成了。

动作确认

com.oculus.vrshell-20200218-204038_1_1.gif

最后导入Oculus,确认是否能够正常运行吧。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1