【Unityネタ】鏡に映る3Dモデルを差し替える

こちらはブログからの転載になります。そのままコピーしたので所々レイアウトがおかしい所があるかも。
https://raspberly.hateblo.jp/entry/UnityAdventCalendar2019_13



この記事は[Unity Advent Calendar 2019](https://qiita.com/advent-calendar/2019/unity)、13日目の記事です。
昨日は[@Kan_Kikuchi](http://kan-kikuchi.hatenablog.com/)さんによる、「[誰でも簡単に使える最強のAudio(BGM, SE)Manager【Unity】](http://kan-kikuchi.hatenablog.com/entry/AudioManager_2019)」でした。

<iframe class="embed-card embed-webcard" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" title="Unity Advent Calendar 2019 - Qiita" src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fqiita.com%2Fadvent-calendar%2F2019%2Funity" frameborder="0" scrolling="no"></iframe>
<cite class="hatena-citation"><a href="https://qiita.com/advent-calendar/2019/unity">qiita.com</a></cite>

今回はUnityネタをやっていきます。
テーマは「**鏡に映る3Dモデルを差し替える**」です。
[去年のアドベントカレンダー](https://qiita.com/advent-calendar/2018/unity2)の派生になります。まだの方はこちらからチェック!

<iframe class="embed-card embed-blogcard" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" title="3Dモデルの影を別の影に差し替える - Raspberlyのブログ" src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fraspberly.hateblo.jp%2Fentry%2F2018%2F12%2F02%2F000000" frameborder="0" scrolling="no"></iframe>
<cite class="hatena-citation"><a href="https://raspberly.hateblo.jp/entry/2018/12/02/000000">raspberly.hateblo.jp</a></cite>

↑去年の記事を公開後、以下のような反応がありました。
(かなり前のツイートですが、この記事自体も去年に書き始めたものです)

> 鏡に映る姿だけ違うとか出来るとなお良し
> — みそじゃが (@Misojaga) [December 3, 2018](https://twitter.com/Misojaga/status/1069397155041882112?ref_src=twsrc%5Etfw)

面白そうなアイデア！
アニメのOPでありそうな表現です。今回はこれを実現してみます。

![f:id:Raspberly:20191212024003p:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/R/Raspberly/20191212/20191212024003.png "f:id:Raspberly:20191212024003p:plain")



### 開発環境

Unity 2019.3.0f
Magic Mirror Lite ver1.2.0

Unity2017.4.28f1 
VRCSDK-2019.09.18.12.05_Public

※他**2019.2f1**、**2018.4.11f1**で動作確認済みです

### アプローチ

今回どういう方法でやるかについて。

**RealWorld**(現実世界)と**MirrorWorld**(鏡の世界)の2つのレイヤーを作成。
**CameraにはMirrorWorldは映らず**、**鏡にはRealWorldが映らない**ように、
それぞれのオブジェクトを各レイヤーに割り当てます。

やってることはとても簡単で、数回マウスをポチポチするだけでできます。

### シーンの準備

最初にシーンを作っていきます。

#### キャラクターの用意

前回に引き続き、**SDユニティちゃん**と**ホラーちゃん**を使用します。どちらも無料アセットです。
**現実世界ではユニティちゃんがいて、鏡には怪物が映る**といった感じです。

<iframe style="width: 202px; height: 260px; border: 0px;" src="https://api.assetstore.unity3d.com/affiliate/embed/package/84992/widget?aid=1101l7KK9"></iframe>
<iframe style="width: 202px; height: 260px; border: 0px;" src="https://api.assetstore.unity3d.com/affiliate/embed/package/47871/widget?aid=1101l7KK9"></iframe>

キャラクターは重なるように置いておきましょう。&nbsp;

![f:id:Raspberly:20191212112914p:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/R/Raspberly/20191212/20191212112914.png "f:id:Raspberly:20191212112914p:plain")

ホラーちゃんは初期状態だと**横を向いているので直したくなりますが**、
アニメーションをするといつも通りになるので**そのままでOK**。

ここは**それぞれ好きなキャラクターで**大丈夫です。
キャラクターが用意できない方はCubeを使いましょう。

### レイヤーを分ける

#### レイヤーの作成

**Project Settings/Tags and Layers**からレイヤーを分けていきます。
今回は「RealWorld」と「MirrorWorld」の2つのレイヤーを新たに作成しました。

![f:id:Raspberly:20191210105315p:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/R/Raspberly/20191210/20191210105315.png "f:id:Raspberly:20191210105315p:plain")

#### オブジェクトのレイヤー設定

各オブジェクトのレイヤーを設定します。

![f:id:Raspberly:20191210105500p:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/R/Raspberly/20191210/20191210105500.png "f:id:Raspberly:20191210105500p:plain")

ユニティちゃんは「**RealWorld**」、ホラーちゃんは「**MirrorWorld**」を設定します。

![f:id:Raspberly:20191212021153p:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/R/Raspberly/20191212/20191212021153.png "f:id:Raspberly:20191212021153p:plain")

![f:id:Raspberly:20191212021219p:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/R/Raspberly/20191212/20191212021219.png "f:id:Raspberly:20191212021219p:plain")

ちなみに、大量のオブジェクトをガッツリわけたい場合は、ルートのオブジェクトを作り、
子オブジェクトにしてあげると、一括変更も楽で管理しやすくなるのでオススメです。

![f:id:Raspberly:20191210105820p:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/R/Raspberly/20191210/20191210105820.png "f:id:Raspberly:20191210105820p:plain")
親のレイヤーを変更すると、子もまとめて変更してくれます。

![f:id:Raspberly:20191210105740p:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/R/Raspberly/20191210/20191210105740.png "f:id:Raspberly:20191210105740p:plain")

### Cameraに映らないようにする

特定レイヤーのオブジェクトがCameraに映らないようにします。
これは簡単にできます。

Cameraコンポーネントの**Culling Mask**から、描画するレイヤーを設定できます。
**映したくないレイヤーはチェックボックスを外しましょう**。
Everythingは全てのレイヤーにチェックを入れ、Nothingは全てのレイヤーのチェックを外します。
今回はMirrorWorldレイヤーをCameraに映らないようにしたいので、**MirrorWorldのチェックを外しま**す。
![f:id:Raspberly:20191210104052p:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/R/Raspberly/20191210/20191210104052.png "f:id:Raspberly:20191210104052p:plain")
これでホラーちゃんはCameraに映らなくなりました。
![f:id:Raspberly:20191212021447p:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/R/Raspberly/20191212/20191212021447.png "f:id:Raspberly:20191212021447p:plain")

ちなみにこちらのCulling Maskは各種Lightにも同じパラメータがあり、
**レイヤーごとにDirectionalLight等を作成することでライティングを分けることもできます**。

### 鏡を作る

鏡を作りましょう。Unityにおいて鏡を作る方法は複数あります。
前回の[Unity Advent Calendar 2019 #3](https://qiita.com/advent-calendar/2019/unity3) 11日目の記事にて紹介した無料アセット「**Magic Mirror Lite**」と
「**MirrorReflection**」「**VRCSDKの鏡**」の3つで動作確認をしています。

#### 鏡に映るレイヤーを制限する

そのままだと鏡には全てのオブジェクトが映ります。
これに制限を加え**「RealWorld」レイヤーのオブジェクトだけ**映らないようにします。

やり方は**Curring Maskのチェックを外す**だけです。(鏡によって多少パラメータ名が違うかもしれません)

#### Magic Mirror Liteで鏡を作る場合
<iframe style="width: 202px; height: 260px; border: 0px;" src="https://api.assetstore.unity3d.com/affiliate/embed/package/34824/widget?aid=1101l7KK9"></iframe>

アセットをインポート後、**Assets/MagicMirror/Prefab/Mirror.prefab**を設置。
Mirror Scriptコンポーネントの**Refrect Layers**からチェックを外しておきます。
![f:id:Raspberly:20191211150237p:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/R/Raspberly/20191211/20191211150237.png "f:id:Raspberly:20191211150237p:plain")

#### MirrorReflectionで鏡を作る場合
こちらを参考にマテリアルとスクリプトを用意します。コピペするだけです。
<iframe class="embed-card embed-webcard" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" title="UnityのMirrorRefrectionによる鏡の表現 - Qiita" src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fqiita.com%2FUnagiHuman%2Fitems%2F6fae8e52d9c5c73ce3b0" frameborder="0" scrolling="no"></iframe>
<cite class="hatena-citation"><a href="https://qiita.com/UnagiHuman/items/6fae8e52d9c5c73ce3b0">qiita.com</a></cite>

それらをPlaneにアタッチして、Mirror Reflectionコンポーネントの**Reflection Layers**から、
RealWorldのチェックを外します。
![f:id:Raspberly:20191212093947p:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/R/Raspberly/20191212/20191212093947.png "f:id:Raspberly:20191212093947p:plain")

#### VRCSDKの鏡を使う場合
SDKのunitypackageをインポート後、**
Assets/VRCSDK/Prefabs/World/VRCMirror.prefab**をシーンに配置します。
VRC_Mirrior_Reflectionコンポーネントの**Reflect Layers**から**RealWorld**のチェックを外します。
![f:id:Raspberly:20191212021819p:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/R/Raspberly/20191212/20191212021819.png "f:id:Raspberly:20191212021819p:plain")

### 完成品

これで完成です。
鏡に映る3Dモデルを無事差し替えることができました。
![f:id:Raspberly:20191212020616g:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/R/Raspberly/20191212/20191212020616.gif "f:id:Raspberly:20191212020616g:plain")
「やあユニティちゃん・・・・・いや、誰だお前はユニティちゃんじゃないな！」
？？？「グググ・・・ヨク気ヅイタナ・・・」&nbsp;

みたいな演出ができるかもしれませんね！

MirrorReflectionとVRCSDKの方でも動作確認済です。
↓はVRCSDKの鏡

![f:id:Raspberly:20191212023739g:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/R/Raspberly/20191212/20191212023739.gif "f:id:Raspberly:20191212023739g:plain")

### 応用技:世界を変える

上の例ではキャラクターのみを差し替えていますが、ステージ・パーティクル・<span style="text-decoration: line-through;">スカイボックス</span>など、
全てを包括した**世界そのもの**を差し替えることもできます。(スカイボックスは無理だった)

やり方はキャラクターと同じで、レイヤーを切り替えるだけです。
3Dモデル以外のパーティクルも同様です。

現実世界は普通の町だが、**鏡の中だと廃墟**だったり。
**鏡の中だけ雨が降っていたり**火の海だったりできるわけですね。
![f:id:Raspberly:20191212013529g:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/R/Raspberly/20191212/20191212013529.gif "f:id:Raspberly:20191212013529g:plain")
あなたの目は本当の世界を映していますか？

### 注意点

#### キャラクターの注意点
キャラクターの位置はもちろん、**アニメーションも同期させるように注意**。
RealWorldとMirrorWorldのキャラクターは**同じAnimatorに**しておくといいでしょう。

#### 描画処理に注意
鏡全般に言えますが、巨大な鏡の場合は注意が必要です。
キャラクターのみなら大丈夫ですが、巨大な建築物やステージだと処理負荷が高くなることも。

### おまけ:Sceneビューでもレイヤー分け
Camera(Gameビュー )と鏡に映るレイヤーを制限することができましたが、
**Sceneビューに映るレイヤーも制限する**ことができます。
Unity Editorの左上にあるLayersから、**目のマークを押すだけ**です。
![f:id:Raspberly:20191212161756p:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/R/Raspberly/20191212/20191212161756.png "f:id:Raspberly:20191212161756p:plain")
シーン内がごちゃごちゃしてきたら試してみるといいでしょう。

<iframe class="embed-card embed-blogcard" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" title="シーンビューに特定のレイヤーのみ表示する - テラシュールブログ" src="https://hatenablog-parts.com/embed?url=http%3A%2F%2Ftsubakit1.hateblo.jp%2Fentry%2F20120907%2F1347029757" frameborder="0" scrolling="no"></iframe>
<cite class="hatena-citation"><a href="http://tsubakit1.hateblo.jp/entry/20120907/1347029757">tsubakit1.hateblo.jp</a></cite>

### まとめ

・レイヤーを分けることで、カメラと鏡に映るオブジェクトを制限できる
・現実世界のオブジェクトと、鏡面世界のオブジェクトで**レイヤーを分ける**。
・Cameraと鏡、それぞれ**表示するレイヤーを変更**する。

&nbsp;使い道としては、「**本当の姿を映す**」「**自分にしか見えない存在を映す**」
「**キャラクターの感情表現**(笑顔だけど本当は悲しんでいるみたいな)」などでしょうか。

ちなみにRealWorldかMirrorWorld**どちらかの3Dモデルだけ**にすれば、
**鏡に映らないキャラクター**や**鏡にしか映らないモンスター**を作ることができます。
どちらにせよ表現の幅が広がるのはいいことです。

&nbsp;以上となります。
&nbsp;明日の[Unity Advent Calendar 2019](https://qiita.com/advent-calendar/2019/unity)は[@monry](https://twitter.com/monry)さんによる投稿です。

&nbsp;わかりにくいところなどがありましたら、コメントにお願いします。