Oculus Questのハンドトラッキングでボーンを視覚的に表示する
Oculus Questのハンドトラッキングに割り当てられているボーンを視覚的に表示してみましょう。デバッグやテストをする際に少しわかりやすくなるかも...?
割り当てられているボーンIDを確認する
OVRSkeletonにボーン関連の情報が集約されており、以下のプロパティからIList型でボーンの情報にアクセスできるようです。
skeleteon = GetComponent<OVRSkeleton>(); skeleteon.Bones ← IList型で取得できる
型はOVRBoneで自身のID、親のインデックス、Transform型を持つ以下のようなクラスとして宣言されています。このクラスを使用すればIDや親子関係も取得できそうです。
public class OVRBone { public OVRSkeleton.BoneId Id { get; private set; } public short ParentBoneIndex { get; private set; } public Transform Transform { get; private set; } public OVRBone(OVRSkeleton.BoneId id, short parentBoneIndex, Transform trans) { Id = id; ParentBoneIndex = parentBoneIndex; Transform = trans; } }
で、ボーンIDは以下のように宣言されており、
public enum BoneId { Invalid = -1, Hand_Start = 0, Hand_WristRoot = Hand_Start + 0, // root frame of the hand, where the wrist is located Hand_ForearmStub = Hand_Start + 1, // frame for user's forearm Hand_Thumb0 = Hand_Start + 2, // thumb trapezium bone Hand_Thumb1 = Hand_Start + 3, // thumb metacarpal bone Hand_Thumb2 = Hand_Start + 4, // thumb proximal phalange bone Hand_Thumb3 = Hand_Start + 5, // thumb distal phalange bone Hand_Index1 = Hand_Start + 6, // index proximal phalange bone Hand_Index2 = Hand_Start + 7, // index intermediate phalange bone Hand_Index3 = Hand_Start + 8, // index distal phalange bone Hand_Middle1 = Hand_Start + 9, // middle proximal phalange bone Hand_Middle2 = Hand_Start + 10, // middle intermediate phalange bone Hand_Middle3 = Hand_Start + 11, // middle distal phalange bone Hand_Ring1 = Hand_Start + 12, // ring proximal phalange bone Hand_Ring2 = Hand_Start + 13, // ring intermediate phalange bone Hand_Ring3 = Hand_Start + 14, // ring distal phalange bone Hand_Pinky0 = Hand_Start + 15, // pinky metacarpal bone Hand_Pinky1 = Hand_Start + 16, // pinky proximal phalange bone Hand_Pinky2 = Hand_Start + 17, // pinky intermediate phalange bone Hand_Pinky3 = Hand_Start + 18, // pinky distal phalange bone Hand_MaxSkinnable = Hand_Start + 19, // Bone tips are position only. They are not used for skinning but are useful for hit-testing. // NOTE: Hand_ThumbTip == Hand_MaxSkinnable since the extended tips need to be contiguous Hand_ThumbTip = Hand_Start + Hand_MaxSkinnable + 0, // tip of the thumb Hand_IndexTip = Hand_Start + Hand_MaxSkinnable + 1, // tip of the index finger Hand_MiddleTip = Hand_Start + Hand_MaxSkinnable + 2, // tip of the middle finger Hand_RingTip = Hand_Start + Hand_MaxSkinnable + 3, // tip of the ring finger Hand_PinkyTip = Hand_Start + Hand_MaxSkinnable + 4, // tip of the pinky Hand_End = Hand_Start + Hand_MaxSkinnable + 5, // add new bones here Max = Hand_End + 0, }
個々のボーンのIDは以下の図のように割り当てられています。
ボーンの表示 & 指ごとに色分けしてみる
ボーンを視覚的に表示し指単位で色分けするスクリプトを作ってみました。以下のスクリプトをOVRHandPrefabにアタッチすれば、確認できます。実行時はOVR Mesh Rendererを無効にしておきましょう。
using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Linq; public class BoneInfoSample : MonoBehaviour { OVRHand _hand; OVRSkeleton _skeleton; List<GameObject> _spheres = new List<GameObject>(); void Start() { _hand = GetComponent<OVRHand>(); _skeleton = GetComponent<OVRSkeleton>(); var boneColor = new Dictionary<string, Color>() { { "Start",Color.black}, // スタート位置 { "Thumb",Color.red}, // 親指 { "Index",Color.green}, // 人差し指 { "Middle",Color.blue}, // 中指 { "Ring", Color.cyan}, // 薬指 { "Pinky",Color.magenta}, // 小指 { "Forearm",Color.yellow}, // 前腕部 }; foreach (var bone in _skeleton.Bones) { // Sphereを生成しボーンに割り当てる var sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere); sphere.transform.position = bone.Transform.position; sphere.transform.localScale = new Vector3(0.01f, 0.01f, 0.01f); sphere.transform.parent = bone.Transform; // 指単位で色を変える var color = boneColor.FirstOrDefault(x => bone.Id.ToString().Contains(x.Key)); sphere.GetComponent<Renderer>().material.color = color.Value; _spheres.Add(sphere); } } void Update() { // トラックが外れたらSphereを消す foreach (var sphere in _spheres) { sphere.SetActive(_hand.IsTracked); } } }
できました!
OVRSkeletonには「Capsules」が定義されていてここに衝突判定用のCapsule Colliderが入っている予感。次回はこの辺りを見ていこうと思います。