MagicLeapハッカソンでARゲームを作ったの呼吸

# はじめに

はじめまして。ごだと申します。

2020年9月に「[Magic Leap Challenge](https://x-garden.co.jp/ml-challenge)」というハッカソンに参加させていただきました。
デバイスを1週間貸していただけて、家での開発ができるという素晴らしいイベントでした。
その中で気づいたことを今回まとめてみましたので、お役に立てれば幸いです。

# ゲームデザイン

「触覚」をコンセプトにした音楽ゲームを作りました。
プレイヤーはテーブルを指で叩くことで移動してくるノーツを処理することができます。
（譜面を作り込む時間の余裕がなく、BGMとSEを合わせられてないのですが雰囲気を感じていただければ幸いです）
![2020-09-12_21h10_00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227584/76ecd35b-d9b9-55ba-7009-6131fec40e7d.png)
動画：https://youtu.be/ckV3ReiJ7og

実装にあたり、空間メッシュとハンドトラッキング機能を活用しました。
単純ではありますが、テーブルより僅か上にノーツを処理するためのボタンを配置することでARでは得づらい触覚という体験を加えることができました。

# 触覚

近年AR技術はどんどん進化を続けています。
多くのデバイスや技術が開発され、今では周囲の環境を映像として取り込むだけでなく、空間の特徴点・メッシュ構造・深度・輝度など現実世界の多くの事柄をパラメータとして取得できるようになりました。
クリエイターはそれらを活用して、ホログラムをより自然に現実に溶け込ませることができるようになりました。
![fov-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227584/5472bbb1-c573-9af4-215d-fa9cb2b6af75.jpeg)
自分もその流れに則り、ARを考える際に現実とホログラムをどう重ねるかを大事にするようにしています。
今回は触覚という感覚を中心にして、テーブルを叩く音や手に伝わる振動とホログラムを連動できればと考えました。

# 視野角

現状のARグラス開発で難しいのは視野角の問題かと思います。
視野角がVRほどは広くなく、MagicLeapでは50度となっています。
また、MagicLeapは手前37cmは非表示領域となり、ホログラムを表示することはできません。

ホログラムが見切れてしまうとその瞬間ではどうしても没入感が途切れてしまうので、視野を意識してデザインを行うことはとても大事だと思います。
![fov-4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227584/f3d14e07-a5c4-f2d0-81dd-17758f3e95f3.jpeg)
自分が今回作ったゲームはそれを意識したデザインができていないのですが、振り返ってみてこうすればよかったというアイデアはあるので列挙したいと思います。

```
1. 手前に表示されるホログラムは小さくして、大きいものを出さない。
2. プレイ前にキャリブレーションを入れて、視野に収まるように事前に全体のオフセット、スケールを調整する。
3. ビネットのようなエフェクトを入れて、視野の境界をぼかす。
```

3に関しては、Kazuya Hiruma様の [ARグラスで 魅力的な絵作り](!https://www.slideshare.net/hirumakazuya/ar-202547902) という資料を拝見させていただき、素晴らしいアイデアだと感じております。

# 明度

ARでホログラムの色合いをどのようにするかという話題になります。
絵作りの話になるので正解はないのですが、自分はARでは明度の高い色を中心にした方がいいと思っています。明度が高いと以下の２つのメリットがあると考えているためです。

```
1. 見やすい。
2. 現実からホログラムが浮き出て見えて、近未来感を演出できる。
```

100%主観ではあるのですが、自分が仕事でARコンテンツを作る際もこちらの方が評判がいいのであながち間違ってはないんじゃないかなと思っています。

Unityでこれに対応するのは難しくありません。
シーンのアンビエントライトを明るめにすれば影の表現は薄まりますが、画面全体を明るく仕上げることができます。以下はアンビエントカラーをデフォルトの `RGB(54, 58, 66)` から `RGB(212, 212, 212)`に変化させたときの違いを表しています。3Dオブジェクトのシェーダーには`Mobile/Diffuse`を使用しています。

■ RGB(54, 58, 66)
![2020-11-21_13h37_50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227584/780d5a57-f197-8aea-4bd1-518685049489.png)

■ RGB(212, 212, 212)
![2020-11-21_13h36_00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227584/931caf1a-ce2a-0f3f-455f-f6958e674a0e.png)

# 影

影は物体がどのような形状なのか、複数の物体がどのような位置関係にあるのかなど空間に多くの情報を補足してくれます。今回自分が作ったゲームにおいて、ノーツは2種類の軌道を描きます。

(1)ドアから豚やユニコーンが出現して突進してくる
![IMG2020112114203s3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227584/6a1d6b83-0164-4872-0ba8-bdf34480dbdb.jpeg)
(2)空中のドラゴンが地を這う炎を射出してくる
![IMG20201121142033.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227584/be302f51-ac92-93cb-000f-1ec2611c6cdb.jpeg)
このように1は平面的な軌道なのですが、2は立体的な軌道を描くようになっています。
今回はこの立体的な軌道をプレイヤーに分かりやすく伝えたかったので、影の実装を行いました。

ARKitPluginのMobileARShadowを参考にしました。
**MLShadow.shader**
https://github.com/HippoAR/Unity-Technologies-unity-arkit-plugin/blob/master/Assets/UnityARKitPlugin/Examples/Common/Shaders/MobileARShadow.shader

```MLShadow.shader
Shader "Custom/MLShadow"
{
    SubShader {
        Pass {
            Tags { "LightMode" = "ForwardBase" "RenderType"="Opaque" "Queue"="Geometry+1" "ForceNoShadowCasting"="True"  }
	        LOD 150
        
            CGPROGRAM
 
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_instancing
            #include "UnityCG.cginc" 
            #pragma multi_compile_fwdbase
            #include "AutoLight.cginc"
  
            struct appdata
            {
                float4 vertex : POSITION;
                
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };
  
            struct v2f
            {
                float4 pos : SV_POSITION;
                LIGHTING_COORDS(0,1)
                
                UNITY_VERTEX_OUTPUT_STEREO
            };
  
            v2f vert(appdata v) {
                v2f o;
                
                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_INITIALIZE_OUTPUT(v2f, o);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
                
                o.pos = UnityObjectToClipPos (v.vertex);
                TRANSFER_VERTEX_TO_FRAGMENT(o);                
                return o;
            }
 
            fixed4 frag(v2f i) : COLOR {
            
                UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
            
                float attenuation = LIGHT_ATTENUATION(i);    
                attenuation = (attenuation*.5+.5);
                
                if (attenuation >= 1)
                {
                    return 0;
                }
                else
                {
                    return fixed4(.2,.2,.2,1);
                }  
            }
 
            ENDCG
        }
    }
    Fallback "VertexLit"
}
```
![2020-11-21_21h26_10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227584/99d4e424-44b1-e31b-189c-d9774808f673.png)
大きめのPlaneをすべての3Dモデルの下に配置し、上のシェーダーを設定して影を落とします。ARグラスは黒の範囲を描画しないため、`LIGHT_ATTENUATION`の値を反転して影の部分が白くなるように使っています。また「シングルパスインスタンシングレンダリング」へ対応させるためのマクロも要所に挟んでいます。こちらを対応しないとホログラムが片目にしか表示されません。

# 音

Unityは3Dサウンドに対応しており、音の発生源とプレイヤーの距離によって音量を変えることができます。視覚だけでなく聴覚を利用して空間を表現することで、より説得力のある体験を届けることができます。
![2020-11-22_17h01_55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227584/ad431c16-3a64-d7e6-3fc8-45f0df23c270.png)
以下の手順で3Dサウンドに対応させることができます。

1. 音の発生源に`AudioSource`をアタッチする。
2. `SpatialBlend`の値を1にする。
3. `MinDistance`、`MaxDistance`を設定する。（この間で音が減衰する）

# デバッグ

ARは周囲の環境に作用する技術であり、エディタだけで変更の確認を行うことは難しいです。
それを解決するために各種デバイスがエミュレータを提供していたり、[UnityMARS](https://blogs.unity3d.com/jp/2020/06/08/introducing-unity-mars-a-first-of-its-kind-solution-for-intelligent-ar/)のようなツールが開発されはじめています。

MagicLeapにはそれに対する回答として **「Zero Iteration」** という仕組みが用意されています。
既に用意されている様々な部屋モデルの上にホログラムを表示し、入力をエミュレートすることができます。
Unityエディタと同期しているところが素晴らしく、エディタで動的に状態を確認したり、操作を加えたりできます。
![2020-11-30_23h15_16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227584/90f4f890-e389-d800-c204-17ca9a946623.png)
今回のハッカソンではこのツールのおかげで確認作業を効率的に行うことができました。

# まとめ

MagicLeapはやれることが多い素晴らしいデバイスで、1週間楽しくAR開発を行うことができました。
今後もARで色々なアプリを作っていけたらと思います。
ありがとうございました。