VRとARを併用したXR作品をSTYLYで作る際のTips

本記事は[STYLYアドベントカレンダー Advent Calendar 2021](https://qiita.com/advent-calendar/2021/styly) 18日目の記事です

こんにちは、ふしっきーです。

少し前になりますが、自撮りをクソコラして夢の国へ行ける
「クソコラランド」
というXR作品を制作し、Stylyに公開しました。
STYLY Mobileを使ってスマホで誰でも、クソコラ体験できるといったものです。

紹介動画
<iframe width="560" height="315" src="https://www.youtube.com/embed/nUBu8BWY3tg" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

作品URL
https://gallery.styly.cc/scene/98da6971-a746-4768-8737-696d08bc7122

体験方法など
https://twitter.com/fusikky/status/1463131706521636866?s=20

こちら[NEWVIEW AWARDS 2021](https://newview.design/awards)にも提出しまして、ありがたいことに[ファイナリスト](https://styly.cc/ja/news/newview-awards-2021-4/)に選んでいただきました。よければこちら是非体験してみてください！

本作品はスマートフォンを使ったモバイルAR体験からVR体験へのトランジションを含めた作品で「VRとARを併用したXR作品」に分類されるようです。

こういった作品はあまり見かけないので、VRとARを併用したXR作品をStylyで作る際のTipsについて記録しておこうと思います。

本稿では
- [STYLY Studio](https://gallery.styly.cc/studio)
- Unity 2019.3.6f1 (Stylt推奨バージョン 2021/12現在) 
- [PlayMaker](https://assetstore.unity.com/packages/tools/visual-scripting/playmaker-368?locale=ja-JP) (StyleではC#が使用できないため)
の使用を想定しています。

筆者のStyly歴が短いため、ほぼUnityの知識で解決しようとしている点ご容赦ください（Stylyの機能うまく使えばもっと楽に実装できるかも）

## 予備知識
本稿は前提として**UnityとSTYLY Plugin for Unity・PlayMaker**を用いてStylyで作品を作った経験がある方向けの記事となります。そちらの経験がない場合は事前に以下の記事を読んでいただくと理解が早くなると思います。

https://styly.cc/ja/manual/unity-asset-uploader/

https://styly.cc/ja/manual/styly_mobile/

## 作品の体験フロー

本作品でのXR体験を要素分解していきます。大まかな体験フローは以下となります。

1. 現実空間でゲートを配置（AR体験）
2. パスポートが2DUIとして出現（AR体験）
3. カメラ映像から自撮りをして、自撮り画像をパスポートにはめ込む（AR体験）
4. パスポートがゲートに吸い込まれ、ARの世界からVRの世界へトランジションする（AR～VR体験）
5. VR空間では右下のボタンで移動（前進）することが可能（VR体験）

# 技術解説目次
作品の体験フローについて、それぞれ技術的にどのように実現したかについて、主にUnity EditorおよびPlaymakerを使った実装の解説をしていきます。

1. [Unityで制作したprefabをStylyアプリ上でAR配置](#-Unityで制作したprefabをStylyアプリ上でAR配置)
2. [2DUI(uGUI)の表示](#-2DUI(uGUI)の表示)
3. [カメラ映像からスクリーンショットを取得する](#-カメラ映像からスクリーンショットを取得する)
4. [AR体験からVR体験へのトランジション方法](#-AR体験からVR体験へのトランジション方法)
5. [AR体験中にもStylyのVR UI(前進ボタン)を表示する](#-AR体験中にStylyのVR UI(前進ボタン)を表示する)

## Unityで制作したprefabをStylyアプリ上でAR配置
![164.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71629/8aec328a-4a99-5e88-97b2-ca19b28b1e13.png)

以下、UnityからStylyにアップロードする単位はprefabにしており、全ての要素をprefabに詰め込んでいます。sceneとしてアップロードするやり方もあるのですが、prefabにした方が位置合わせなどの取り回しが楽になるのでそうしています。

![173.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71629/dab37695-5e96-979b-ead1-6543b46dd549.png)
図 すべてを詰め込んだ all in one prefab の hierarchyの例

Unityで制作したprefabをStylyアプリ上でAR配置するには、Stylyモバイルの標準機能で実現できます。Unityから対象のPrefabをStylyにアップロードし、STYLY Studio上に配置します。そしてモバイルのStylyアプリから作品を起動すると以下の画面になり、作品を現実空間に配置できます。配置した位置が原点になるので、そこから良い感じに見える位置にゲートを配置しています。

![196.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71629/4f013ba3-3a42-acb9-afd7-d7469d9eda13.png)

![162.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71629/9aa60eee-a335-6be1-6dbf-86e66badf36c.png)

Prefabのアップロード手順は [予備知識](#-予備知識) の項目の解説記事を参考にしてください。

## 2DUI(uGUI)の表示

![167.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71629/9b17551d-56f7-b1e5-d318-d9877b1cdcbf.png)

パスポートの表示はUnityのuGUIを使用しています。UI要素(Canvas)もさきほどの all in one prefabに詰め込んでおり、そのままStylyで使用できます。
その際の注意点としてCanvas以下のLayerを全てdefaultにしないとStylyでエラーが出てしまいます。

![174.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71629/4972304d-f9e6-4933-60c0-50d8bec49ef5.png)
図 Layerが異なるエラー

![176.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71629/4335c3cd-0f84-ac09-4278-230aa6632ed6.png)
図 CanvasのLayerをdefaultに変更

## カメラ映像からスクリーンショットを取得する

ここが本作品の一番の肝であり、一番苦戦したところでもあります。
### カメラ映像の取得
カメラ映像の取得自体はSTYLY Plugin for Unityの機能を使い、Playmakerからカスタムアクション`GetARCameraImage`を用いて可能です。
以下の処理ではカメラ映像をGetARCameraImageアクションでcameraTexture変数に格納、SetTextureステート内のSetMaterialTextureアクションでCameraTexPlaneオブジェクトのMaterialの_MainTexに設定しています。

![177.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71629/6fa29f8c-94a3-a0c2-bb88-2677a25cc803.png)
![178.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71629/98aa6f2e-3767-00fa-9ce6-c54a4fe05f02.png)

この処理でカメラ映像が取得できるのですが、カメラ映像は毎フレーム更新されるためスクリーンショットとして静止したテクスチャを取得することができません。

### カメラ映像を静止したテクスチャとして取得

これを以下のようなハックを用いて「静止したテクスチャ」として取得します。
一言で言うと**「Unityのカメラ映像のTargetTextureへの更新は、カメラを削除することで停止する」**原理を利用します。

![192.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71629/b65f07be-f008-ecba-5cf1-4203fc672f9e.png)
図 Camera2を削除することでTargetTextureへの更新を停止

「カメラ映像の取得」の章をそのまま流用します。CameraTexPlaneオブジェクトはQuadのGameObjectにしましょう。
続いてStylyで扱うメインカメラとは別のカメラを用意します。（以後Camera2と呼びます）Camera2で、先ほど用意したCameraTexPlaneを映します。続いてRenderTextureを新規作成し、Camera2のTargetTextureを先ほど作成したRenderTextureに設定します。こうすることでカメラ映像がCamera2を通して、RenderTextureに毎フレーム更新されます。こちらのRenderTextureの更新は、Camera2のGameobjectを削除することでストップさせることが可能になります。

クソコラランドでは、RenderTextureをUIのImageに設定し、シャッターを切るタイミングでCamera2のGameobjectをDisableにし、更新をストップしています。あとはこのRenderTextureをあらゆるオブジェクトで使いまわせばよいのです。

![191.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71629/b01eb685-d315-09ca-2e6c-35a313ccc323.png)

上記のような手法で、カメラ映像を静止させることができました。

こちらはStyly作品[CHIHAYABURU](https://newview.design/works/chihayaburu/)の開発ノウハウを参考にさせていただきました。

※ただし、こちらの手法は一部のAndroid端末では正しく動作しない（赤いテクスチャが表示されてしまう）ため非推奨となっているようなのでご注意ください。

## AR体験からVR体験へのトランジション方法
ARの世界からトンネルをくぐってVRの世界へワープする処理なのですが、
こちらに関してもいくつかTipsがあります。

## 移動とフェードイン
ゲートに吸い込まれてトンネルを通り抜ける演出は、3Dの空間全体を移動させています。自分自身（カメラ）を動かすのは少し面倒なので、周りのGameObjectを動かしています。また、その際トンネルのマテリアルのアルファをAnimationでフェードインさせています。迫りくるトンネルをフェードインすることにより、視界全体をフェードインする処理と同等の体験になります。

## トンネルの穴をふさぐ

この時、トンネルの先が見えなくなるようにしているのですが、ここにも落とし穴がありました。
それは、どんなに円筒型のトンネルを長くしてもトンネルの先が見えてしまいました。
![183.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71629/e0e9209b-60aa-a805-7741-46703ed6e7d9.png)
円筒型

どんなにトンネルを長くしても変わらないため、これはおかしいと思ったところ、どうやらStylyで使用しているカメラのfar clipが100であることに起因していたようです。つまり、100m先のオブジェクトは表示されないということです。
（UnityEditorのカメラのfar clipはデフォルト1000)

ちなみに、styly cameraのfar clipを変更する方法もあるのですが、円筒のままで実現するには相当遠くまでトンネルを伸ばす必要があるので、結局トランジションに使うモデルを円筒型から円錐型にすることで回避しました。

![184.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71629/bcc038d9-ec29-0f38-6888-31a07b788c0b.png)
円錐型

上記を組み合わせ、最終的には以下のような見た目になりました。
![kusokora-trans.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71629/08086fca-f7b7-da57-1e46-3adadfb96030.gif)

今回は使用しませんでしたが、Cameraのfar clipを変更する方法を記載しておきます。

![193.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71629/96f33086-5340-8922-6497-6e85d90238b4.png)

ちなみに、far clipを変更した際は、必ずもとに戻すのを忘れないでください。（作品体験後もパラメータが自動で初期化されないため）

## AR体験中にStylyのVR UI(前進ボタン)を表示する

本作品は最初にAR体験を行うにも関わらず、右下のVR移動UIが表示されています。
![185.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71629/c3c67b75-30c6-3d05-6323-1d1e00f1fffb.png)

StylyでAR作品を鑑賞する際は、右下の移動UIが表示されないのですが、こちらの仕様をガン無視して表示しています笑

自撮りを顔ハメするという作品の性質上、カメラを起動するAR機能は必須だったんですよね。ですが、VR空間でも移動したい！ということでAR機能も使いつつVR移動UIも表示しています。

どのように実現しているのか解説します。

**Styly作品のAR、VRの判定はSkyboxの有無で行われ、それは最初の数フレームの間で判定される**ようです。その判定時にSkyboxを表示しておけばStyly的にはVR作品として認識されるため、移動UIが表示されます。そして移動UIが表示された後、Skyboxを削除すれば、背景にカメラ映像が表示され、AR体験ができるというわけです。そして、VR空間へトランジションする際に再びSkyboxを設定してVR体験にシフトしているわけです。なかなか忙しい処理ですね

- 最初は仮のSkyboxを表示（VR作品としてStylyが起動）
![186.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71629/264e10b0-9549-cffa-a25b-4dd6bf119586.png)

- 0.5秒後にSkyboxを削除（Skyboxが消え、カメラ映像が表示される）
![187.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71629/120175f2-9c38-2e18-d5e3-3af26b3f8413.png)

- AR→VRトランジション時にSkyboxをを設定（Skyboxが設定され、カメラ映像が非表示になり、VR体験ができる）
![188.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71629/e41b8837-6f7b-12aa-bc07-816db5f2a3d1.png)

上記の処理を行うことで、AR体験を行うにも関わらずStylyのVR UI(前進ボタン)を表示することを可能にしています。

# まとめ
ということで、多少ニッチな手法も使用しましたが、上記の様な手法を駆使してStylyで「VRとARを併用したXR作品」を完成させることができました。C#を使えないというのはなかなかプログラマ泣かせですが、作品が完成するころにはPlaymakerがかわいく思えてくるものです。

冒頭でも触れましたが、大分Unityでどうにかしている部分があるので、今後Stylyの方で機能がアップデートされれば、今回の実装のようなことも簡単にできるようになってくると思います！

またこの作品を作る上で、Stylyスタッフのテクニカルサポートの無しには実現できませんでした。改めて感謝申し上げます！ありがとうございました！