真っ白な空間を作る (Unreal Engine 4)

## この記事で作る世界

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/d236ab83-1628-f9e5-aef4-cbc6f46503c2.png)

目指すのは、この「真っ白で何もない世界」。

[映画『The Matrix』に出てきたシーン](https://youtu.be/tGgCqGm_6Hs?t=90)や、[ジョージ・ルーカス監督のデビュー作『THX 1138』のシーン](https://www.lucasfilm.com/productions/thx-1138/)など、SF映画でたまに目にする光景です。白いキャンバスのような空間なので何でも自由にできる可能性を感じつつ、方向感覚も見失う上に空間上に入り口も出口も存在しないため VR とかで体験を行うと頭が混乱してしまいそうな雰囲気がありますね。

### 周りのアクターをすべて白に設定してみると...

この世界は、周りのアクターを白く設定すれば簡単に作れそうな気がしますが、例えば Base Color を白に設定しただけだと思ったよりも白くなりません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/013bce27-ad27-7c0d-02eb-c7aa0c8e0ba3.png)

Emissive Color を使うことによって全体的に白くなりますが、床に影が出なくなってしまったり、周囲を囲むアクターの境界線が僅かに残ってしまう問題など、この方法も簡単にはいきません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/19c6c6f4-6225-92d3-0bd2-a596fef35f0b.png)

実装方法をネットで調べてみても、それらしき答えはぱっとは出てきません。

- [Quick noob question: How to set completely white World/Environment color?](https://forums.unrealengine.com/t/quick-noob-question-how-to-set-completely-white-world-environment-color/64235)

今回はそんな白背景の空間を、きちんと床に影を落とした立体感のある空間になるように作ってみようと思います。

## 作り方のポイント

作り方はいろいろな方法があると思いますが、今回はシンプルに実装しようと思い __表示したいアクターとその影の部分以外のピクセルをすべて白く塗る__ というアプローチを取りました。 Post Processing を使います。

鍵となるのは2点。 __白く塗るピクセルをどうやって切り出すか__ と、 __影をどうやって切り出すか__ 。

1点目については __Stencil Buffer__ を今回使用します。 [Stencil Buffer](https://en.wikipedia.org/wiki/Stencil_buffer) はレンダリングで使われる Color Buffer や Z Buffer と似たような形で、追加のデータを保持することができるバッファーになります。 Stencil という単語自体は下図のような中がくり抜かれたシート状のものを指しています。このシートを壁に貼り付けてスプレーを吹きかけると、下の2枚目の図ののように壁に文字を印字できます。 Unreal Engine 4 でも同様の使い勝手が可能で、ピクセルごとに処理を適用させる部分と適用させない部分を分けることができます。

<img src="https://upload.wikimedia.org/wikipedia/commons/8/86/PartsOfStencil.png" alt="PartsOfStencil.png">

<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/5/52/Quadrilingual_danger_sign_-_Singapore_%28gabbe%29.jpg/1200px-Quadrilingual_danger_sign_-_Singapore_%28gabbe%29.jpg" alt="Quadrilingual danger sign - Singapore (gabbe).jpg" width=360pt>

Unreal Engine 4 における Stencil Buffer の例がこちら。[公式のチュートリアル動画](https://www.youtube.com/watch?v=PiQ_JLJKi0M) では特定のオブジェクトに対してのみ色を残してそれ以外は desaturate する方法を説明しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/b5e16db9-f155-5c04-df24-551a00a4c085.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/058f1549-8abb-6851-23db-96a6d4cf4983.png)

2点目の影の切り出しについては、このあと具体的なノードの接続方法と一緒に説明します。

## 具体的な手順

具体的な作り方を見ていきます。今回は Unreal Engine 4.27.1 を使用しました。

### Step 1. Stencil Buffer を有効にする

Stencil Buffer は Unreal Engine 4 ではデフォルトでは無効となっています。まずは有効にしましょう。

1. プロジェクト設定を開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/96e5fe0b-ae8c-e331-1466-6a356f53fb15.png)

2. 「エンジン」の「レンダリング設定」を開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/323b64e8-00e0-e3be-50e1-fbe0aa834ab1.png)

3. 「ポストプロセス」のところにある「カスタム深度ステンシルパス」を「Enabled with Stencil」に設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/6e2eaa0a-8a6c-9dac-43f3-bfa49aaacd6e.png)

これで Stencil Buffer が有効になります。

### Step 2. 描画したい Actor とそうでない Actor を設定する

次に、描画したい Actor とそうでない Actor を Stencil Buffer に保持するための設定を行います。

1. 描画したい Actor を選択し
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/a7ff7299-18da-74db-e051-d4b30be882a8.png)

2. 「Render CustomDepth Pass」にチェックを入れて、「CustomDepth Stencil Value」を1にします（値は何でも良いですが、このあと設定する Post Process においてこの数値に応じて白く塗るか否か判断するので、0以外のわかりやすい数字が良いでしょうk）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/bc750dd9-8574-8d20-b1dd-5deb73739c67.png)

3. 描画したくない Actor については、とりあえず何も手を加えなくて良いです

ちなみにですが、設定した Stencil Buffer の値を可視化する方法として、以下のように表示モードを設定するとわかりやすいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/2671e55a-23e7-65c6-0072-3e80d7957627.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/b00a927b-b9ae-144c-07f6-012f402b09b9.png)

「001」という数字が記載されているのが見て取れますが、これは Stencil Buffer の値です。

### Step 3. Post Process において、Stencil Buffer の値に応じて塗り分けをする

次に、 Stencil Buffer の値に応じて白く塗るかそのままにするか色分けをする Post Process Material を作成します。

1. Post Process 用のマテリアルを作成する

マテリアルを作成したあと、 Material Domain を Post Process に設定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/661284c5-3afd-2fef-66b7-50b67459ee43.png)

次に __Blendable Location を Before Tonemapping に設定します__ 。文字通り Tonemapping の前にこの Post Process を実行することを意味しますが、この設定は影の切り出しやアンチエイリアシングなどに影響がするため必要となります。

またもう一点重要な点で、 Enable Stencil Test にチェックを入れ、 Not Equal 1 という条件を設定する必要があります。こうすることで、 __Stencil Buffer の値が1ではないピクセルに対してこの Post Process の処理が適用されることになり、値が1のピクセルについては Post Process が影響せずそのままになります__ 。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/9cc2d2b3-c87a-496a-cb59-d78c20bae525.png)


2.ワールドに設置する

Post Process Material をワールドに設置し、 Post Process マテリアルを設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/e771abb0-18ee-0e07-e1c0-752b1e44d2dd.png)

なお、この時 Infinite Extent (Unbound) にチェックを入れるのを忘れないようにしましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/cee062c1-feb2-b3fc-6816-3a1509256977.png)


3.影の部分を切り出し、それ以外のピクセルを白く塗る

Post Process マテリアルのノードは今回、以下のように作りました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/90591fcb-8f50-8341-4763-6110e1deb2e7.png)

__先程説明を後回しにしていた影の切り出しの処理ですが、実はここでそれを実装しています__ 。「SceneTexture:BaseColor (as stored in GBuffer)」の値から「SceneTexture:PostProcessInput0」の値を引いているのが見て取れますが、この2つの描画データの差が影に相当する部分となっているため、この２つの差分を見ることによって影だけを切り取ることができます。あとは条件分岐させて白く塗りたいところだけ値を設定しています。

ちなみにですが、白く塗るピクセルは Emissive Color で値を 10 としています。この値は大きくするほど白くなっていきますが、この値を大きくすると Bloom の影響で全体的に白くなってしまったり、 Bloom を切ったとしても Motion Blur の描画結果が少し違和感のあるものになってしまうなど問題があったため、今回は値を __10__ に設定しました。

これで大体求めている結果になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/8d2e2f65-e7a0-162e-af9a-1b35f88549dd.png)

少し全体的に黒みがかっていてコントラストは低い状態となっていますが、このあたりはワールドに設置した Post Process Volume の設定（Bloom や露出、コントラストなど）を変える事によって調整ができると思います。今回私は

- Bloom は強度を0に設定して白っぽくならないように設定
- 露出補正の値は 2 に設定
- 最大輝度は 6.0 に設定

として、この記事の最初の画像のような世界を作成しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/357fe08e-7c26-16a9-2412-93e097383bc9.png)


## 遊んでみる

これで真っ白な空間の完成です。コンセプチュアルな空間なので、いろんなものを配置するだけでなんだか抽象的な空間に仕上がってなかなかいい空間です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/f33625fd-9864-3cf1-eabc-a1acdf43563e.png)

![paikroom.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/445acf4f-e571-22f2-efc7-0be13ee297b9.gif)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/f23506db-512c-8bd4-28b6-40ae19997dc3.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/0b8a925c-9e3d-0094-d308-d0b1cd024d14.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/5f2c6300-93c9-e1de-64ca-a05e6d395115.png)


## NG パターン

最後に一点だけ補足。今回 Stencil Buffer を使ってピクセルを白く塗りましたが、この処理 (Post Processing) を After Tonemapping で実行すると、背景は完全な白になってくれるというメリットがえられるのですが、その一方で影の切り出しが難しくなります。これは、 Tonemapping の影響で、影の切り出しに使っていた「SceneTexture:PostProcessInput0」の値が変化してしまい、「SceneTexture:BaseColor (as stored in GBuffer)」との差分が大きくなってしまうことが原因です。実際、今回の場合でそれを行ってみると、床の色が若干変化してしまった影響で床がそのまま表示されてしまいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/dc437b8b-92dc-efbc-d742-d873ea748f83.png)

それならばと思い、色に対して閾値を設定して、ある色よりも白いピクセルは全部白く塗るという設定を加えてみます。そうすると今度は __エイリアスの問題が発生してしまいます__ （実は影の切り出しとも関係してきてこのあたりの設定は少しややこしくなります）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525978/4e32ee6c-b639-2054-dfcc-289181701e4c.png)

実際にプレーをしてみるとわかるのですが、エイリアスが汚いという問題以前に画面がかなりチラついてしまい、体験として非常に悪いものとなってしまいました。そのためこの方法は、文字通り白の背景が得られるもののあまりオススメができません。