HoloLensではじめるMRDesignLabs - HandCoachを使いこなす

#自作のHoloLensアプリの使い方どう説明します？
HoloLensはジェスチャが入力のメインになります。ジェスチャの種類は多くはないですが初めてのアプリケーションでは操作方法に戸惑う場合が多いと思います。
MRDesignLabs_Unity_LunarModulesは両手ジェスチャー入力でかつTapHoldでの操作が基本になります。そして、操作が複雑（慣れが必要なのですが）です。おそらく説明がないと操作を理解できません。このため、チュートリアルのための機能が付いています。今回はLunarModuleのチュートリアルの機能だけを抜き出し利用できるようするともにサンプルコードで使い方の説明を行いたいと思います。

LunaModuleをデプロイして遊びたい方は[こちら](http://qiita.com/miyaura/items/2ecbebe005dcb070c1db)を参考にしてください。

## 環境などなど
### 開発環境
 * Windows 10 Pro
 * Unity 5.6.1f1
 * Visual Studio 2015 Community Edition Update 3 

### ソースコード

 * [https://github.com/Microsoft/MRDesignLabs_Unity_LunarModule](https://github.com/Microsoft/MRDesignLabs_Unity_LunarModule)
 * [今回のサンプルコードはこちら](https://github.com/TakahiroMiyaura/MRHandCoachSamples)
 
## LunarModuleのチュートリアル

Lunar Moduleではこういう形で機体の操作をチュートリアルで説明しています。手の色が青い状態なのですが、これはそれぞれの手がHoloLensのセンサ内で検出されている状態です。センサー外の場合は赤色になります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/152548/d31a46c5-c7ec-07d8-ee15-00cac6aa3119.png)

この手の表現を行うためのPrefabがHandoCoachとして提供されています。

### HandCoachの説明

HandCoachはPrefabで構成されています。Hierarchyに登録しプロパティを設定することで、設定したジェスチャー操作がアニメーションで表示されます。
1つのHandCoachで片手or両手どちらも対応可能です。また、チュートリアルとして複数の操作を組み合わせる場合、手順分HandCoachを作る必要はありません。実際には１つだけ用意しておき、プログラム側からプロパティを変更することで複数操作のチュートリアルを実現します。

プロパティが多いコンポーネントですのでカテゴリ毎に設定を整理したいと思います。

#### Material settings
HandCoachの外観についての設定をするプロパティ群です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/152548/38259236-4cb1-fbc9-eaa6-6f221eacca2c.png)

| プロパティ名 | 説明 | 選択値など |
|:-:|:--|:--|
| HandMaterial |ジェスチャーに使用するマテリアルを設定します。 | HandCoachMaterial |
| Highlight Color | 手が表示され強調表示されているときの色を設定します。 |- |
| Normal Color | 手が表示され、強調表示されていないときの色を設定します。 | - |
| Tracked Color | センサーが手を検出中であるときの色を設定します。| - |
| Tracking lost Color | センサーが手の検出を喪失している時の色を設定します。| - |
|Color(Highlight)|Highlight Colorで設定した色をマテリアルのどこに反映させるかを設定します。| <UL><li>\_InnerColor(手全体)</li><li>\_RimColor(輪郭)</li></UL> |
|Color(Tracking)|Tracked Color及びTracking lost colorで設定した色をマテリアルのどこに反映させるかを設定します。| <UL><li>\_InnerColor(手全体)</li><li>\_RimColor(輪郭)</li></UL>|
|Use float property for transparency|ジェスチャーの浮き上がらせ方をfloat数値系のプロパティで行うか、Color系のプロパティで行うかを選択します。trueの場合はFloat値での変更になります。Color系は透過度を変更します。| - |
|Range(Transparency)|ジェスチャーの浮かび上がり方に関する設定値。透過度を変更して表示するか、輪郭の光具合で表現するかを選択する。|<UL><li>\_Alpha(色の透過度)</li><li>\_RimPower(輪郭の光具合)</li></UL>||
|Color(Transparency)|ジェスチャーの浮かび上がり方に関する設定値。どの色に対して変更を掛けるかを設定します。|<UL><li>\_InnerColor(手全体)</li><li>\_RimColor(輪郭)</li></UL>|
|hands to Highlight|ジェスチャーの手にハイライト色を適用するか設定します。|<UL><li>None</li><li>Left</li><li>Right</li></UL>|



#### Tracking settings

センサーの検出に対するジェスチャーオブジェクトの設定を行います。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/152548/4b21fa89-d884-921d-037a-1f4c264e55d4.png)

| プロパティ名 | 説明 | 選択値など |
|:-:|:--|:--|
|CheckTracking |trueの場合、センサーが手を検出/未検出に応じて透過色を自動的に設定します。| <UL><li>None</li><li>Left</li><li>Right</li><li>Both</li></UL>|
|Auto-ghost hands when tracking lost|センサーで手が未検出の場合、表示されている手の透過度を変更するかどうか設定します。| true/false|
|Ghosting|手が未検出の場合、透明度を変更する手を設定します。|<UL><li>None</li><li>Left</li><li>Right</li><li>Both</li></UL>|
|Tracking|変更不可。センサーにより検出されている手を取得します。|<UL><li>None</li><li>Left</li><li>Right</li><li>Both</li></UL>|

#### Gesture settings
ジェスチャーの挙動に対する設定を行います。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/152548/6ee95077-733e-f54d-30ce-a9253a2e37d1.png)

| プロパティ名 | 説明 | 選択値など |
|:-:|:--|:--|
|Hands to show|ジェスチャー表示する手を設定します。|<UL><li>None</li><li>Left</li><li>Right</li><li>Both</li></UL>|
|Auto Lower On Invisible|不可視時に自動的に手のジェスチャーを下げるように設定します。|true/false|
|RightGesture|右手で表現するジェスチャーを設定します。|<UL><li>None</li><li>Tap</li><li>TapHold</li><li>TapHoldRelease</li><li>Bloom</li><li>Ready</li></UL>|
|LeftGesture|左手で表現するジェスチャーを設定します。|<UL><li>None</li><li>Tap</li><li>TapHold</li><li>TapHoldRelease</li><li>Bloom</li><li>Ready</li></UL>|
|RightMovement|右手のジェスチャー操作の表現を設定します。|<UL><li>Static：一度だけ設定に応じたジェスチャーの動きを再現します。</li><li>PingPong:設定応じたジェスチャーの動きを繰返し(初期状態→最終状態→初期状態→...)実施します。</li><li>Directional:設定応じたジェスチャーの動きを繰返し実施します（初期状態→最終状態1セットで繰り返す）</li></UL>|
|LeftMovement|左手のジェスチャー操作の表現を設定します。|<UL><li>Static：一度だけ設定に応じたジェスチャーの動きを再現します。</li><li>PingPong:設定応じたジェスチャーの動きを繰返し(初期状態→最終状態→初期状態→...)実施します。</li><li>Directional:設定応じたジェスチャーの動きを繰返し実施します（初期状態→最終状態1セットで繰り返す）</li></UL>|

#### Right hand direction & Left hand direction
ジェスチャー操作の中にポジションの移動が含まれる場合は以下のパラメータをチェックし移動に対するアニメーションを有効にします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/152548/dea015d6-2e83-8c4d-2911-ff4487efe037.png)

| プロパティ名 | 説明 | 選択値など |
|:-:|:--|:-:|
|None|動きなし|-|
|Left|左にポジションを移動するジェスチャー|-|
|Right|右にポジションを移動するジェスチャー|-|
|Front|前方にポジションを移動するジェスチャー|-|
|Back|手前方向にポジションを変更するジェスチャー|-|
|Up|上にポジションを移動するジェスチャー|-|
|Down|下にポジションを移動するジェスチャー|-|


## 使い方

使い方自体は非常に簡単で、HierarchyパネルにProjectパネルから「HandCoach.prefab」をドラッグ&ドロップします。チュートリアルとしていろいろなジェスチャーの説明をする場合でもジェスチャー操作をプログラム側から変更できるのでオブジェクトとしては１つあれば問題ありません。
配置後チュートリアルとして設定したいジェスチャーをプロパティで設定すれば画面に手の動きがアニメーションで表示されます。
例えば、今回のサンプル用に追加したHandCoachのいくつかのパターンではこのような動きになります。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">Lunar Moduleに実装されているHandCoachの調査と拡張。元はセンサーのトラッキング時に青になる。これを正しい操作状態のときに青くなるようにしてみる。使い方はわかってきたので整理しよう。&#13;<a href="https://twitter.com/hashtag/MRDesignLabs?src=hash">#MRDesignLabs</a> <a href="https://t.co/mGPyP5laOi">pic.twitter.com/mGPyP5laOi</a></p>&mdash; takabrz (@takabrz1) <a href="https://twitter.com/takabrz1/status/897809253305466880">2017年8月16日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

実際の操作方法としてジェスチャーの動きを伝えることができるためヘルプ用のシーンなどでこれを使う形になります。

### 自分のアプリに導入する場合

このHandCoarchについてはLunar Module付属の機能のためHolotoolKit-Unity,MRDesignLabsに加えてMRDesignLabs_LunarModuleも必要になります。実際にチュートリアル用にHandCoachを使う場合はLunar Moduleのgithubから必要なものだけを抜き出す形で使うことになります。

#### 抽出するファイル群

必要な構成は以下の通りです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/152548/641c04ad-1bc1-1d0a-685a-b6ff46510659.png)

* HoloToolkitフォルダ全て
* MRDesignLabsフォルダ全て
* MRDesignLabs_LunarModule以下
 * \Animation以下
     *  HandCoachAnimator.controller
     *  HandLeftHandedness.anim
     *  HandMoveBack.anim
     *  HandMoveDown.anim
     *  HandMoveForward.anim
     *  HandMoveLeft.anim
     *  HandMoveRight.anim
     *  HandMoveUp.anim
     *  HandRightHandedness.anim
 * \Editor以下
     *  HandCoachInspector.cs
 * \Materials以下
     * Shaders\HandCoachShader.shader
     * HandCoachMaterial.mat
 * \Meshes以下
     * \Materials\coachBody_Mat.mat
     * HandCoach.fbx
 * \Prefabs以下
     * HandCoach.prefab
 *\Scripts以下
     * HandCoach.cs
 * \Textures以下
     * HandCoachTexture.psd
     * HandPresent.psd
     * HandPressed.psd

## サンプルコードと拡張

上記の方法でHandCoach部分だけ抽出したサンプルを作成しました。
HandCoachの機能でTracking Settingsという設定項目があります。この設定を利用するとHoloLensのセンサーが手を検出している場合に、ジェスチャーオブジェクトの色をトラッキング中の色に変更することができます。これによりセンサーに認識されているかを判別することができます。

使い方を理解するために、この機能を少し拡張し「正しいジェスチャー状態の場合にトラッキング中の色に変更する」機能を追加したいと思います。どのような動作になるかは先の動画を見ていただくとわかると思います。まずセンサーが手を検出している状態ではReadyジェスチャーが青くなります。その後Tap動作を行うとTap操作に対応するジェスチャーが青くなります。また、TapAndHold状態で手のポジションを変更するとすると移動した向きにあったジェスチャーが青くなります。この機能については[前回説明したLocalHandInput](http://qiita.com/miyaura/items/d44e50f4cb422fdf0500)の機能も利用しています。

### DirectionTrackableHandCoachHelper

[https://github.com/TakahiroMiyaura/MRHandCoachSamples](https://github.com/TakahiroMiyaura/MRHandCoachSamples)にHandCoach拡張用にDirectionTrackableHandCoachHelperコンポーネントを追加しました。このコンポーネントはHnadCoachコンポーネントを必須にしています。ですのでHierarchyパネルに追加したHandCoach.prefabにこのコンポーネントを追加する形で利用します。
プロパティは以下の通りです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/152548/68473f9c-7463-9305-5ef2-f301ed4b9aef.png)

| プロパティ名 | 説明 | 選択値など |
|:-:|:-:|:-:|
| Target Right Gesture  | 検出したい右手のジェスチャー  | <UL><li>None</li><li>Tap</li><li>TapHold</li><li>TapHoldRelease</li><li>Bloom</li><li>Ready</li></UL>  |
| Target Right Direction  | TapAndHold中の右手の移動方向  | <UL><li>None</li><li>Left</li><li>Right</li><li>Front</li><li>Back</li><li>Up</li>><li>Down</li></UL>  |
| Target Left Gesture  | 検出したい左手のジェスチャー    | <UL><li>None</li><li>Tap</li><li>TapHold</li><li>TapHoldRelease</li><li>Bloom</li><li>Ready</li></UL>  |
| Target Left Direction  | TapAndHold中の左手の移動方向  | <UL><li>None</li><li>Left</li><li>Right</li><li>Front</li><li>Back</li><li>Up</li>><li>Down</li></UL> |
| Tap Threshold  | ジェスチャーの内、Tap、TapAndHold→Releaseを区別するための閾値。TapはジェスチャーとしてTapAndHold+ReleaseになるためHoldの時間次第でTapなのか、TapAndHold+Releaseなのかを区別します。  | 0.1  |
| RHand | 右手設定済みのLocalHandInput  | - |
| LHand  | 左手設定済みのLocalHandInput  | - |

## 最後に
基本的には機能を提供するMRToolkit-Unityに比べると実験要素の強いMRDesignLabsですが、便利な機能が豊富です。
皆で使えば、MRToolkit-Unity側にも追加されたりすると思うので、たまにはMRDesignLabsも楽しんでください。