OculusQuestのハンドトラッキングで右手左手を簡単に判別する


1.はじめに

技術研究として2019年12月に実装された、OculusQuestのハンドトラッキング技術を用いた開発を行いました。
途中オブジェクトを掴むとき右手と左手の判別をしたくて簡単に実装してみました。
ちなみに開発したものはこちら ↓
https://lab.taki.co.jp/virtual-cube-puzzle/

2.問題点

OculusQuestのハンドトラッキングでオブジェクトを掴むときの流れとして

手がオブジェクトに触れる → オブジェクト側が触れたことを検知 → 触れた状態でピンチ → 手のオブジェクトの子オブジェクトになる → ピンチ解除 → 親子関係解除

という感じです。
物体を掴むことに関してはこちらの記事を参考にさせていただきました。
https://qiita.com/Kujirai_sakananosuke/items/4ea801e0ed3e08e1cccb

最初の手がオブジェクトに触れるという部分はOnCollisionStay()で当たり判定を付けます。
UnityのAssetStoreで提供されているOculus IntegrationのOVRHandPrefabからだと関節ごとのBone情報で手の当たり判定を検知できるのですが、左右の手に入っているBoneの名前が完全に一緒のため手が触れたことまでで、左右どちらの手が触れたかの判別ができません。
今回は左右判別する部分だけ抽出してまとめます。

3.実装

調べると色々やり方はありそうでしたが時間がなかったので簡単な方法で実装しました。
左右のOVRHandPrefabと同階層に3Dオブジェクトをそれぞれ入れて別々に当たり判定を付けることにしました。

上記のようにRightCube,LeftCubeを追加したらそれぞれスクリプトをアタッチします。

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

public class RightCube : MonoBehaviour
{
    public bool _TouchingRight;
    void OnCollisionStay(Collision Collision)
    {
        _TouchingRight = true;
    }
    void OnCollisionExit(Collision Collision)
    {
        _TouchingRight = false;
    }
}
LeftCube.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LeftCube : MonoBehaviour
{
    public bool _TouchingLeft;
    void OnCollisionStay(Collision Collision)
    {
        _TouchingLeft = true;
    }
    void OnCollisionExit(Collision Collision)
    {
        _TouchingLeft = false;
    }
}

RightCube,LeftCubeは簡単でこれだけです。
続けて触れられる側のオブジェクトにもスクリプトをアタッチします。(上の画像のHierarchy内でいうと一番下のCube)

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

public class TouchCube : MonoBehaviour
{
    private RightCube _RightCube;
    private LeftCube _LeftCube;
    private bool _touchRight;
    private bool _touchLeft;
    void Start()
    {
        _RightCube = FindObjectOfType<RightCube>();
        _LeftCube = FindObjectOfType<LeftCube>();
    }
    void Update()
    {
        _touchRight = _RightCube._TouchingRight;
        _touchLeft = _LeftCube._TouchingLeft;

        if(_touchRight == false && _touchLeft == false){
            GetComponent<Renderer>().material.color = Color.gray;
        }
    }
    void OnCollisionStay(Collision other)
    {
    if (other.gameObject.name == "Hand_Index2_CapsuleRigidBody" ||
        other.gameObject.name == "Hand_Index1_CapsuleRigidBody" ||
        other.gameObject.name == "Hand_Thumb2_CapsuleRigidBody" ||
        other.gameObject.name == "Hand_Thumb1_CapsuleRigidBody" )
        {
            if(_touchRight == true && _touchLeft == false){
                GetComponent<Renderer>().material.color = Color.magenta;
            }else if(_touchLeft == true && _touchRight == false){
                GetComponent<Renderer>().material.color = Color.cyan;
            }else if(_touchRight == true && _touchLeft == true){
                GetComponent<Renderer>().material.color = Color.yellow;
            }
        }
    }
}

今回は触れる物体が一つなので問題ありませんが、左右の判別だけだとオブジェクトが複数ある時に一つ触れると他のオブジェクトも連動してスクリプトを走らせてしまいます。
なのでBoneを検知したうえで右手か左手かを判別させています。

最後にRightCube,LeftCubeにAlpha値0にしたマテリアルをアタッチすればオッケーです。
以上スマートではないけど簡単な右手左手の判別方法でした。