https://torikasyu.com/?p=927
の続きです。
さて、次は別のサンプルを使ってSpatialMappingを更に調べてみます。
HoloToolkit-UnityのHoloToolkit-Testにある、SpatialProcessingシーンを実行してみます。
(HoloToolkit-1.5.7で試していますので、バージョンが違うと多少違うかもしれません)
実行すると、こんな風になります。
通常、SpatialMappingのポリゴンデータは凹凸がありますが、そこに処理を加えることによって、平面が滑らかな板に置き換わっています。
(同じような用途のSpatialUnderstandingプレファブを配置したときには、メッシュのまま滑らかなポリゴンになりますが、その動きともかなり違う感じです。)
平面(Plane)になることにより、そこに対して別のコンポーネントをアタッチしたり、Planeの上に他のGameObjectを置いたりするのがすごく楽になりそうに感じますので、ここを調査してみたいと思います。
サンプルのHierarchyに置いてあるSpatialProcessigには、
SpatialProcessingTest.cs
SurfaceMeshesToPlanes.cs
RemoveSurfaceVerticles.cs
の3つのコンポーネントがアタッチされています。
ではSpatialProcessingTestの中身をざっくりと見ていきましょう。
===
■Start()
SpatialMappingManagerとSurfaceMeshesToPlanesのインスタンスを操作しています。
どちらもHoloToolkit本体にあるクラスですね。
SurfaceMeshesToPlanesでPlaneを生成するのですが、完了時にイベントが発行されるように設定しています。
■Update()
meshesProceedがfalseかつ規定時間を過ぎた場合にPlaneの生成処理処理を行うようにしています。CreatePlanes()関数を呼び出し、その中で、SurfaceMeshesToPlanesのMakePlanes()を呼び出しています。
SurfaceMeshesToPlanesでPlaneが生成完了した際に発生するイベント内では、PlaneのタイプがFloorのものが規定数になっているかをチェックして、規定数に達した場合はRemoveVeriticlesによってもともとのSpatialMappingのポリゴンを削除、規定数に達しない場合はmeshesProceedをfalseにすることによって解析を続ける、という処理になっています。
===
なかなかに複雑な動きですが、ここから下記のことがわかりました。
・SurfaceMeshesToPlanesクラスは、MakePlanes()関数を呼び出すことにより、SpatialMappingからPlaneを生成してくれる。
・生成されたPlaneはFloorなどの種別を持っている(いいですね!使えそうですね)
・RemoveVerticesは、もともとのSpatialMappingの頂点を消してくれる。
これを使って、最小限シンプルな動きを作ってみたいと思います。
いつものようにHoloLensCamera、InputManager、SpatialMapping、BasicCursorを配置後、空のGameObjectを作成し、SurfaceMeshesToPlanes.csと下記のスクリプトをアタッチします。
using System.Collections; using System.Collections.Generic; using UnityEngine; using HoloToolkit.Unity.SpatialMapping; public class MySpatialProcess : MonoBehaviour { // Use this for initialization void Start () { SurfaceMeshesToPlanes.Instance.MakePlanesComplete += SurfaceMeshesToPlanes_MakePlanesComplete; SurfaceMeshesToPlanes.Instance.MakePlanes (); } private void SurfaceMeshesToPlanes_MakePlanesComplete(object source, System.EventArgs args) { List<gameObject> planes = new List<gameObject> (); planes = SurfaceMeshesToPlanes.Instance.ActivePlanes; foreach (GameObject plane in planes) { SurfacePlane surfacePlane = plane.GetComponent<surfacePlane> (); if (surfacePlane != null) { print (surfacePlane.PlaneType); print (surfacePlane.transform.position); } } } }
内容としては、単純にSpatialMappingからPlaneを生成していて、まだRemoveVerticesは使用していません。
SurfaceMeshesToPlanesにPlane生成完了時のイベントを設定した後にMakePlanes()を呼んでいるだけととてもシンプルです。そして、完了時イベント内では、Planesの情報をprintしていますが、その結果、それぞれ独立したGameObjectとして取得できていて、PlaneTypeにより床なのか壁なのかテーブルなのか、という情報もわかります。(スクリーンショットのログ部分参照)
これで、壁だったら絵画を置いて、天井だったら穴をあけて(キリンの首用)、テーブルだったらUnityちゃんを座らせる、みたいな処理ができるようになりそうです。
SpatialUnderstandingを使うともっと細分化してタイプを取得できるようなのですが、まずは単にSpatialMappingプレファブを置いただけのノンコーディング状態よりも進歩しました!