MRが楽しい

MRやVRについて学習したことを書き残す

ユニティちゃん大地に立つ

以前、紹介したユニティちゃんを表示するアプリは、指定の座標にユニティちゃんを表示しているだけです。
空間を認識して立っている訳ではないため、壁の前でアプリを起動すれば、ユニティちゃんは壁の中に表示されてしまいますし。
高いところで表示すれば、足は浮いたまんまです。
f:id:bluebirdofoz:20170412154501j:plain

これでは現実世界と仮想現実を複合するMRらしくありません。ポケモンGOなどで利用されるARをhololensで試しているだけです。
さて、今日のお遊び枠です。
・【HoloLens開発】ユニティちゃんとHoloLensで戯れる - 空間認識編 -
 http://bril-tech.blogspot.jp/2016/11/hololens-spatialmapping.html


利用を見送ったHoloToolkit-Unityを今回は利用します。
・HoloToolkit-Unity を使う
 http://www.naturalsoftware.jp/entry/2016/06/22/170925

紹介ページの通りですが、SpatialMappingというPrefabを利用することで、
作成した空間マッピングにオブジェクト(ここではユニティちゃん)を置けるようになります。


説明の通り実施してみましたが、今回は容易ではなく、2点の問題が発生しました。

まず最初に、HoloToolkit-Unityをプロジェクトに取り込んだところ、下記のエラーが発生しました。

・Assets\HoloToolkit\CrossPlatform\Scripts\Reflection\TypeUtils.cs 13行目
 'Type' does not contain a definition for 'GetTypeInfo' and no extension method 'GetTypeInfo' accepting a first argument of type 'Type' could be found (are you missing a using directive or an assembly reference?)

・Assets\HoloToolkit\CrossPlatform\Scripts\Reflection\ReflectionExtensions.cs 31行目
 'Type' does not contain a definition for 'GetBaseType' and no extension method 'GetBaseType' accepting a first argument of type 'Type' could be found (are you missing a using directive or an assembly reference?)

・Assets\HoloToolkit\CrossPlatform\Scripts\Reflection\ReflectionExtensions.cs 46行目
 'Type' does not contain a definition for 'GetBaseType' and no extension method 'GetBaseType' accepting a first argument of type 'Type' could be found (are you missing a using directive or an assembly reference?)

当該コードを以下の通り、修正することで対応
・TypeUtils.cs

//return type.GetTypeInfo().BaseType;
return type;

・ReflectionExtensions.cs

//var baseType = type.GetBaseType();
var baseType = type;

正直なところ、自身の環境では何故このエラーが発生したのか。
また、この修正方法で本当に問題ないのか。きちんと理解できていません。

・Type.BaseType in Portable Class Library
 http://stackoverflow.com/questions/25351860/type-basetype-in-portable-class-library
・A lot of reflection functionality like Type.BaseType is not available anymore in dnxcore50
 https://github.com/Microsoft/dotnet-apiport/issues/268

この辺りの情報を見るに、WinRTのAPIが変わった?
今回は深く追いませんが、何かあった時の備忘録として書き残しておきます。


さてビルドは成功して、アプリはきちんと動作しました。
しかし、今度はユニティちゃんが床を通り抜けて奈落の底へ落ちていく事象が発生しました。

これの原因は一目瞭然でした。
SpatialMappingの作成には十数秒ほど時間がかかります。
このため、床が作成される前にユニティちゃんが重力に引っ張られて床を通り抜けていってしまうのです。

折角なので、前回作成した機能を流用して対応します。
理屈は簡単、タップ操作を行って初めて、ユニティちゃんに重力属性が与えられるよう修正しました。

利用したのは前回のGazeGastureManager.csと、新たにUnityCommands.csという以下のスクリプトを自作しました。

using UnityEngine;

public class UnityCommands : MonoBehaviour {
    private Rigidbody rigidbody;                      // Rigidbodyへの参照

    // Use this for initialization
    void Start ()
    {
        rigidbody = GetComponent<Rigidbody>();
    }

    // タップ操作時に呼ばれるOnSelect関数
    void OnSelect () {
        // RigidbodyのuseGravity変数をtrueにして重力を発生させる
        rigidbody.useGravity = true;
    }
}

これらのスクリプトを以下の通り、ユニティちゃんのオブジェクトに設定します。
また、勝手に落ちないよう、重力のデフォルト値は無効にしておきます。
f:id:bluebirdofoz:20170412154730j:plain


さて、アプリを起動してみます。起動直後はこれまで通り、ユニティちゃんが宙に固定されています。
f:id:bluebirdofoz:20170412154800j:plain
空間マッピングで床が生成されたのを確認したら、タップ操作を実行すると…
f:id:bluebirdofoz:20170412154843j:plain
この通り、ユニティちゃんが少し落下してそのまま床の上に立ちました。成功です
f:id:bluebirdofoz:20170412154856j:plain


今回のプロジェクトで、仮想空間のオブジェクトが現実世界を認識して動きました。
ようやくMRらしいアプリが実装できたと言えます。


因みに今回のプロジェクトの副産物として現実世界の障害物や奥行きを認識できるようになるという効果があります。
(床が認識できているので当然と言えば当然ですが)

例えば、先ほどのユニティちゃんの手前に段ボールを置いてみると…
f:id:bluebirdofoz:20170412155103j:plain
障害物を認識し、3Dモデルが障害物の奥に隠れる形で描写されるようになっています。