2017年9月14日木曜日

HoloLensの開発 SpatialUnderstandingDllTopologyで壁にオブジェクト配置してみる

お疲れ様です。ZuQ9->Nnです。
今回も、前回に引き続きSpatialUnderstandingの話題です。

SpatialUnderstandingには検知した壁、天井、床にオブジェクト配置する機能があります。
今回はSpatialUnderstandingDllTopologyというクラスを用いて
壁にオブジェクト配置に挑戦してみます。

Unity 5.6.2f1HoloToolkit-Unity-v1.5.8.0.unitypackage
HoloToolkit-Unity-Tests-v1.5.8.0.unitypackage を利用します。
まずは、HoloToolkit-Unity-v1.5.8.0.unitypackageをすべてインポート

次にHoloToolkit-Unity-Tests-v1.5.8.0.unitypackageの
MediumRoomWithHomeFurniture.fbxのみ
チェックしてインポートします。
次にプロジェクトの設定を行います。UnityのHoloToolkitメニューから
Configure > Apply Hololens Projectを選択、
表示されたポップアップメニューのApplyをおします。
続いてUnityのHoloToolkitメニューから
Configure > Apply Hololens Capablity Settingを選択、
Spatial PerceptionをチェックしてApplyをおします。
HierarchyのMain Cameraを右クリックで選択
表示されたメニューからDeleteで削除します。
HoloLensCamera、InputManager、Cusor、SpatialMapping、SpatialUnderstandingの
PrefabをHierarchyに置きます。
(HoloLensCamera、InputManagerはProjectのHoloToolkit > Input > Prefabs
CusorはHoloToolkit > Input > Prefabs > Cursor
SpatialMappingはHoloToolkit > SpatialMapping > Prefabs
SpatialUnderstandingはHoloToolkit > SpatialUnderstanding > Prefabsの中です)

HierarchyのSpatialMappingを選択Room Modelのプロパティに
MediumRoomWithHomeFurniture.fbxを選択しアタッチします。
HierarchyのSpatialMappingを選択Spatial Mapping Managerの
Draw Visual MesheのチェックをOFFにします。
UnityのProjectに適当な画像ファイルを追加します。
(今回はskey.pngという空の画像を追加しました。)
HierarchyのCreate > 3D Object Planeを選択し、Planeを作成
作成されたPlaneの名前をposterに変更、大きさを適当に変更し(サンプルでは x0.1 y0.1 z0.1)
rotationのxを90に変更、Unityに追加した画像ファイルをposterのMaterialにします。
HierarchyのposterをProjectにドラグアンドドロップでPrefab化した後
Hierarchyのposterは削除します。

ProjectのCreateからC# Scriptを選択、Scriptの名前をTopologySampleとします。

TopologySampleの中身はこんな感じです。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HoloToolkit.Unity;
using System;
public class TopologySample : MonoBehaviour {
public TextMesh textMesh = null;
public float kMinAreaForComplete = 50.0f;
public float kMinHorizAreaForComplete = 25.0f;
public float kMinWallAreaForComplete = 10.0f;
public GameObject WallPrefab;
private bool triggerd = false;
private void LateUpdate()
{
if (DoesScanMeetMinBarForCompletion)
{
SpatialUnderstanding.Instance.RequestFinishScan();
}
if (!triggerd && SpatialUnderstanding.Instance.ScanState == SpatialUnderstanding.ScanStates.Done)
{
triggerd = true;
SpatialUnderstandingDllTopology.TopologyResult _resultsTopology = new SpatialUnderstandingDllTopology.TopologyResult();
var resultsTopologyPtr = SpatialUnderstanding.Instance.UnderstandingDLL.PinObject(_resultsTopology);
float minWidthOfWallSpace = 0.1f;
float minHeightAboveFloor = 1f;
float minHeightOfWallSpace = 1f;
float minFacingClearance = 0.1f;
var locationCount = SpatialUnderstandingDllTopology.QueryTopology_FindPositionsOnWalls(
minHeightOfWallSpace,
minWidthOfWallSpace,
minHeightAboveFloor,
minFacingClearance,
1,
resultsTopologyPtr);
if (locationCount > 0)
{
Instantiate(this.WallPrefab,
_resultsTopology.position,
WallPrefab.transform.rotation);
}
}
}
private bool DoesScanMeetMinBarForCompletion
{
get
{
if ((SpatialUnderstanding.Instance.ScanState != SpatialUnderstanding.ScanStates.Scanning) ||
(!SpatialUnderstanding.Instance.AllowSpatialUnderstanding))
{
return false;
}
IntPtr statsPtr = SpatialUnderstanding.Instance.UnderstandingDLL.GetStaticPlayspaceStatsPtr();
if (SpatialUnderstandingDll.Imports.QueryPlayspaceStats(statsPtr) == 0)
{
return false;
}
SpatialUnderstandingDll.Imports.PlayspaceStats stats = SpatialUnderstanding.Instance.UnderstandingDLL.GetStaticPlayspaceStats();
if ((stats.TotalSurfaceArea > kMinAreaForComplete) ||
(stats.HorizSurfaceArea > kMinHorizAreaForComplete) ||
(stats.WallSurfaceArea > kMinWallAreaForComplete))
{
return true;
}
return false;
}
}
}
HierarchyのCreate Emptyで空のGame Objectを追加し
GameObjectにTopologySampleのScriptをアタッチ、
TopologySampleのWall Prefabプロパティにposterのprefabをアタッチして完成。
Unityを実行するとこんな感じで壁に、空のポスターが表示されます。
もちろん、SpatialUnderstandingDllTopologyを使わなくても
同じように壁にオブジェクト配置することは可能です。

MicrosoftのHolograms 230 のサンプルはSpatialMappingとSurfaceMeshesToPlanes.csで
壁の検知と壁にポスターを張っています。

SpatialUnderstandingDllTopology.QueryTopology_FindPositionsOnWallsの
メソッドの引数を調整することで細かく壁の位置が指定できるのが特徴ですね。

より細かく制御する場合はSpatialUnderstandingDllTopologyを
用いるといったすみわけかな。

GitHubで見つけたSpatialDemoでは壁だけではなく
SpatialUnderstandingDllTopology.QueryTopology_FindPositionsOnFloor
SpatialUnderstandingDllTopology.QueryTopology_FindPositionsSittable
なんかも利用していますので、併せて参考にしてください。