目指せ脱HoloLens初心者!その1(TapToPlace)

HoloLensの開発はUnityとHoloToolkit-Unityがあればすぐにでも始められるので、ひとまず動かすだけなら簡単です。
HoloLens Meetup Vol.4でゆーじさんが発表されていたように、豆腐を鑑賞するアプリなどは開発環境ができたらば簡単に作ることができます。


そして、HoloToolKit-Unityに入っている便利なプレファブ、中でもSpatialMappingは、Hierarchyに置いちゃうだけで空間の情報が取れて、Collider(あたり判定)が作れてしまうので、Mixed Realityの大きな特徴である「現実空間に作用する」動きがすさまじく簡単に作れてしまいます。
これを使ってこんなアプリを作った方も多いのではないでしょうか?


豆腐と現実の空間が作用して、現実空間に豆腐が当たって跳ね返ってくる様子がわかります。
HoloLensを初めて触った時や、これから初めて触る人にとってはMixed Realityを説明するいい題材になるのですが、このままだとSpatialMappingの中身はよくわかりません。なので、ここから応用してもっと使いこなせるように、中身をいろいろ調査していきたいと思います。
といっても、@d_yama さん初め、HoloLens界の先人が詳細な調査結果を残してくださっています。

なので、このブログではどちらかというと、「すぐに使えるコード」の方向で調べていければと思います。
ではまず手始めとして、HoloToolKitに入っているTapToPlace.csを見てみます。
This repository is for the legacy Mixed Reality Toolkit (MRTK) v2. For the latest version of the MRTK please visit - microsoft/Mixe...
HoloToolKitのバージョンによって場所が変わるようなので、Projectタブの検索ウインドウでファイル名を入れて探してみてください。
そもそもTapToPlace.csの役割は何かというと、このスクリプトをAttachしたGameObjectは、SpatilaiMappingの上のどこかに貼り付けることができるようになる、というものです。
さっきの豆腐を投げるサンプルですと、豆腐が跳ね返ってきてしまいますが、これを使うと豆腐を壁や天井に貼り付けることができるようになります。
豆腐で部屋の飾りつけができるようになるわけですね!!
使い方は、HoloLensCamera、InputManager、SpatialMappingの各prefabを配置して、豆腐(Cube)にTapTopToPlace.csをAttachするだけです。
ということで、TapToPlaceの中身を見てみると・・難しいですね(泣)
ですが、わかりやすく重要なポイントだけを抜き出してみます。
まず、Start()でWorldAnchorManagerに関する初期化をしています。
WorldAnchorManagerは、空間上にGameObjectの場所を固定する機能がありますが、いったん先に進みましょう。
そしてUpdate()部分です。

        protected virtual void Update()
        {
            if (!IsBeingPlaced) { return; }
            Vector3 headPosition = Camera.main.transform.position;
            Vector3 gazeDirection = Camera.main.transform.forward;
            // If we're using the spatial mapping, check to see if we got a hit, else use the gaze position.
            RaycastHit hitInfo;
            Vector3 placementPosition = SpatialMappingManager.Instance != null &&
                Physics.Raycast(headPosition, gazeDirection, out hitInfo, 30.0f, SpatialMappingManager.Instance.LayerMask)
                    ? hitInfo.point
                    : (GazeManager.Instance.HitObject == null
                        ? GazeManager.Instance.GazeOrigin + GazeManager.Instance.GazeNormal * DefaultGazeDistance
                        : GazeManager.Instance.HitPosition);
            // Here is where you might consider adding intelligence
            // to how the object is placed.  For example, consider
            // placing based on the bottom of the object's
            // collider so it sits properly on surfaces.
            if (PlaceParentOnTap)
            {
                placementPosition = ParentGameObjectToPlace.transform.position + (placementPosition - gameObject.transform.position);
            }
            // update the placement to match the user's gaze.
            interpolator.SetTargetPosition(placementPosition);
            // Rotate this object to face the user.
            interpolator.SetTargetRotation(Quaternion.Euler(0, Camera.main.transform.localEulerAngles.y, 0));
        }

まず注目したいのが、

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

です。VR/MRアプリの特徴である、「頭の位置がカメラの位置」「頭の向きがカメラの向き」というのがダイレクトにわかります。
これが分かれば「Holo目からビーム」が簡単に作れますね!!実用的!(?)
そして次の部分がやたら長くて心が折れそうになりますが、この部分もHoloLensアプリ開発で非常に常用な概念が入っています。
少し分解して、一番重要な部分を抜き出すと、これになります。

Physics.Raycast(headPosition, gazeDirection, out hitInfo, 30.0f, SpatialMappingManager.Instance.LayerMask)

Physics.Raycastは、3D空間での当たり判定を調べるためにUnityでよく使う方法で、目からビーム(!)を打って、当たったものを調べる動きになります。
ビームの原点は頭の位置、方向は頭の方向、そして判定レイヤーが「SpatialMappingManager.Instance.LayerMask」になります。
ここから、生成されたSpatialMappigのレイヤーを始めとする情報は、SpatialMappingManagerが保持している、ということがわかりました。SpatialMappingに対して操作をしたければ、SpatialMappingManagerのインスタンスの値を使えばいい、ということが理解できました!
ということで、先ほどのコードは「頭の位置からビームを飛ばして、SpatialMappingに当たった位置」を求めていることになり、HoloLensアプリ開発のいろいろな場面で応用できる考え方になります。
あとはその位置を使ってWorldAnchorで固定していくコードになりますが、自分で作る場合には、別にWorldAnchorを使用しなくても、動かしたいGameObjectのtransform.positionを先ほどのRaycastの結果の位置にすれば、そこにGameObjectを移動させることができるようになります。
また、もう1つの重要頻出表現(?)がTapToPlace.csに入っています。(SpatialMappingとは無関係)
クラスの定義で

public class TapToPlace : MonoBehaviour, IInputClickHandler

と、IInputClickHandlerを継承しています。これがあると、AirTapに反応する動きを作れるようになります。

public virtual void OnInputClicked(InputClickedEventData eventData)
{
}

上記メソッドを用意すれば、AirTapされた時の動きを書けるようになります。
※ゆーじさんの方法、MRDesignLabsを導入した場合は違うかもしれません(未検証)
ちょっと応用としてStart()内に、

InputManager.Instance.AddGlobalListener(gameObject);

と書くと、何もないところ(正確には空間上どこでも)をAirTapした時にOnInputClickedが反応するようにすることができます。先ほどの仕事をしている人に豆腐を投げつけるアプリは、この「どこでもAirTap」と「頭の位置」を使ってCubeをInstantiateし、「頭の方向」を使って、RidgidBodyにAddForceすることにより実現しています。
ということで、TapToPlace.csから、HoloLensアプリ開発に重要な要素がたくさん学べました。
次回はもっとSpatialMappingについて調べていき、脱初心者を目指していきたいです!
https://torikasyu.com/?p=938

スポンサーリンク

シェアする

  • このエントリーをはてなブックマークに追加

フォローする

スポンサーリンク