[UE4][UE5] TranslucencyとDOFとDistortionとPPMの描画優先問題について

検証UE: 4.27.2, 5.0.0
まちがってたらごめんなさい。
UE5は詳しくないので、何か違いとか回避策あったらごめんなさい。教えてください。ざっと見ると同じ感じっぽかった。

Translucencyなマテリアルを使用したメッシュと、
DOF（被写界深度）と、
Distortion（屈折、Refraction）と、
PostProcessMaterialの描画順の問題についてになります。
Deferred Renderingでの検証になります。


# 絡まり合う問題
それぞれが描画順と絡み合うので、色々な問題が発生します。
詳細は後述参照です。

- Translucency
    - **Render After DOF = ON**（デフォルト）
        - → [DOF が掛からない](#translucencyにdofが掛からない)
        - → [Distortion の向こうのオブジェクトが屈折しない](#distortion-の奥に-render-after-dof--on-があると発生する問題)
    - **Render After DOF = OFF** にする
        - → [DOF より近くにある Translucency がボケてしまう事がある](#カメラ位置が変わった場合)
        - → [Distortion の見た目がよろしくない場合がある](#distortion屈折の見た目が変わる)
    - DOF が掛かるようなオブジェクトだけ **Render After DOF = OFF** にしておく
        - → [もし位置が逆転してしまうと Render After DOF = ON のオブジェクトと描画が逆転してしまう可能性がある](#render-after-dof-の設定が混在すると発生する問題)
        - → [Distortion の見た目がよろしくない場合がある](#distortion屈折の見た目が変わる)

　

- Post Process Material
    - **Before Translucency** で描く
        - → [Translucency の Render After DOF = ON のオブジェクトに効果が適用できない。](#blendable-location--before-translucency-がtranslucencyに掛からない)
    - **Before Tonemapping** で描く
        - → [SceneTextureの情報を使っていると、DOF部分の境目の表示が良くない](#blendable-location-を-before-tonemapping-以降に変更することによるdofとの問題)


# UEの描画順
1. **Translucency** (Render After DOF = OFF)
2. **Distortion** (屈折、Refraction）
3. **Post Process Material** (Blendable Location = BeforeTranslucency)
4. **DOF**
5. **Translucency** (Render After DOF = ON)

**※Render After DOF**
「DOFの後に描画するか」。マテリアルの詳細欄の同名パラメーター。Translucencyの描画パス設定。
**UE4 Render After DOF = ON** → **UE5 Translucency Pass = After DOF**
**UE4 Render After DOF = OFF** → **UE5 Translucency Pass = Before DOF**
**UE5 After Motion Blur** は **Before DOF** より更に後のパスかと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/0e05b4d2-55b0-602e-414b-33bf9d195281.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/798fba11-a25a-e45a-78c4-711431d2a888.png)

**※Distortion**
Translucencyなマテリアルで「屈折」パラメーターに値が入った際、背景を屈折させて表示する描画パスです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/6e2a537d-fe38-af97-c0a5-713d07c99c6f.png)

**※Blendable Location**
ポストプロセスマテリアルの詳細欄の同名パラメーター。PostProcessMaterialの描画パス設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/a34ffb27-da21-da9c-4a2c-ad65c7e18d31.png)




# 問題
## TranslucencyにDOFが掛からない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/f025ecb7-85a7-88ec-d9e1-a9f1a15a380e.png)

よく見る問題がこちらだと思います。
こちらは描画順が「**(4)DOF**」→「**(5)Translucency (Render After DOF = ON)**」となっている為、
DOF のボケを描画した後に Translucency を描いている為になります。

これ自体をなんとか対応するには、Translucency マテリアルの「**Render After DOF**」をOFFにする事で回避できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/974eedc9-304f-18ed-5b54-d251f1e2d1b4.png)
奥側のメッシュだけ対応して、無事ボケました。
OFFにした事で Translucency の描画順が「**(5)Translucency (Render After DOF = ON)**」から「**(1)Translucency (Render After DOF = OFF)**」に変わりました。
結果、描画が「**(1)Translucency (Render After DOF = OFF)**」→「**(4)DOF**」の順になったので、ボケるようになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/7814ae26-18e7-cc94-1fff-956ab04f948c.png)

## Translucency の Render After DOF を変更することによる問題
### カメラ位置が変わった場合
先程からカメラの位置が変わり、画面内の配置が変わった場合。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/a4a34fd4-a269-b3b1-9ef7-dc1ecbd908a8.png)
今度は先程マテリアルを「**Render After DOF**」をOFFに差し替えたオブジェクトが画面手前に来ました。
本来は土台のBoxのようにボケてほしくない状況です。

描画順的に「**(1)Translucency (Render After DOF = OFF)**」→「**(4)DOF**」の順なのでボケるようになってしまっています。
（TranslucencyにはDepth(深度)情報が無いので、更に奥の壁のDepthが使用されてDOFが掛けられています）

Translucencyマテリアルの「**Render After DOF**」をONに戻すと、DOFの後に描画を行うので意図した通りボケなくなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/24320374-107d-cc99-c7e4-3da21b57d68b.png)

可能なら状況ごとに「**Render After DOF**」のON/OFFを切り替えれると、カットシーン等でカット毎に対処とかで何とか出来るかもしれません。
（シームレスにカメラが近づいたり離れたりする場合は……何か考慮が必要……）
ただし「**Render After DOF**」のパラメーターは実行時に変更はできず、またマテリアルインスタンスでも変更はできません。
つまり、<font color="OrangeRed">**マスターマテリアル自体でしか切り替えられず、同じマテリアルを２種類用意しなければいけません。**</font>
きびしい。

じゃあ「**Render After DOF**」ONのマテリアルと、「**Render After DOF**」OFFのマテリアル２種類作って、状況に応じて差し替えるか……
と頑張ってみても、また別の問題が発生する場合があります。

### Distortion（屈折）の見た目が変わる

下記が「**Render After DOF**」が **OFF** の状態です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/16492f35-cd53-4997-b6de-000bfd066fe5.png)
下記が「**Render After DOF**」が **ON** の状態です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/852a1a9e-bc74-3e79-8035-6e87eacfa094.png)

マテリアルの中身は同じで、「**Render After DOF**」のON/OFFだけ切り替えました。
<font color="OrangeRed">**Distortion（屈折）部分の色の付き方が「Render After DOF」の状態によって変わります。**</font>
前者 OFF の状態は、「**(1)Translucency (Render After DOF = OFF)**」を描いてから「**(2)Distortion**」で歪ませる
→ (1)Translucency で描いた色も歪む。
後者 ON の状態は、「**(2)Distortion**」で歪ませてから「**(5)Translucency (Render After DOF = ON)**」で 描く
→ (5)Translucency で描く色は歪まない

上記は球で描画しましたが、オブジェクトだとより顕著に違いが出ます。
左が **OFF** 、右が **ON** 。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/d28da3c5-0199-b61e-6449-a9ae1d3bdbe7.png)
屈折の強さによっては色が乗らなくなり、意図した見た目にならない可能性があります。

左が **OFF** 、右が **ON** 。
![c.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/56764fb3-fcfc-7974-6ef5-276a57c4bbcb.gif)
パーティクルは特に動きがあるので、後から屈折で歪んでボコボコした見た目になってしまっています。

### Distortion の奥に Render After DOF = ON があると発生する問題
手前が Distortion しているパーティクル。
奥の青いオブジェクトが Translucency。
左側が **Render After DOF = OFF**、右側が **Render After DOF = ON** になります。
![d.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/320fe27c-edcb-6c7d-85ee-711d0a0b32b9.gif)

左の **Render After DOF = OFF** のオブジェクトは Distortion で歪みます。
しかし、右の **Render After DOF = ON** のオブジェクトは Distortion で歪みません。
**(2)Distortion** の後に **(5)Translucency (Render After DOF = ON)** が描画されてしまうので、<font color="OrangeRed">**Distortion の奥にある Translucency が歪まず描画されてしまいます。**</font>
前後関係が崩れてしまい、厳しい見た目になっています。

### Render After DOF の設定が混在すると発生する問題
手前の赤い板が Translucency の **Render After DOF = OFF**。
奥の青いオブジェクトが Translucency。
左側が **Render After DOF = OFF**, 右側が **Render After DOF = ON** になります。
![e.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/113c6354-dc25-02e9-32e7-56c8836ea901.gif)
<font color="OrangeRed">**手前にある筈の赤い板より、奥右側の青いオブジェクトが手前に描画されてしまっています。**</font>
描画順が、手前の板 **(1)Translucency (Render After DOF = OFF)** の後に、
奥右側のオブジェクト **(5)Translucency (Render After DOF = ON)** となってしまっているのが原因です。

よく見かけるのは、外を歩いている時は問題無いけど、車の中から窓ガラス越しや、家の中の窓越しに見るとおかしい。とかでしょうか。

## Post Process Material の Blendable Location による問題
### Blendable Location = Before Translucency がTranslucencyに掛からない
内容的には前述「[TranslucencyにDOFが掛からない](#translucencyにdofが掛からない)」と同じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/d2998b62-02b2-af78-7a2c-25eaf7fc47c8.png)
注視対象以外を暗くするようなPostProcessMaterialを用意しました。
**Blendable Location = Before Translucency** です。
今は中心の柱を注視しているのに、右側の Translucency に色が乗ってしまっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/3f8393e9-9298-67a0-03ba-4811c0279b81.png)
描画順的に、<font color="OrangeRed">**「**Render After DOF**」が **ON** の Translucency は、
「**Blendable Location**」が **Before Translucency** になっている Post Process Material の後に描画されてしまいます。**</font>

こちらもDOFと同様に Translucency の「**Render After DOF**」を **OFF** にする事で回避できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/79332868-02ef-0a31-7c79-92d3b1ced091.png)
もしくは、Post Process Material の「**Blendable Location**」を **Before Tonemapping** 等にする事でも回避できます。
ただし、こちらで対処する場合は、DOF との描画優先問題が発生してしまいます。

### Blendable Location を Before Tonemapping 以降に変更することによるDOFとの問題
「**Blendable Location**」を **Before Translucency** から **Before Tonemapping** や **After Tonemapping** 等に変更した際の問題です。

こちらは、Post Process Material 内で Scene Texture 系を利用している場合の問題です。
→ SceneTexture 系は **World Position** や、**Scene Depth**、**Custom Depth** 等を使用している場合です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/9461e82e-33cb-c750-9cd7-77d07719068a.png)

**Before Tonemapping** 以降の場合、「**Render After DOF**」が **ON** のTranslucencyにも影響を与えることが出来ます。
その変わりに、DOF の表示での問題が発生します。

カスタムステンシルで、対象以外を暗くする Post Process Material を書きました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/5fc18d4d-e8c8-49e1-aa42-190974489f7c.png)

これを DOF がかかるシーンで見ます。奥の柱と手前のBOXにカスタムステンシルを設定して、それ以外を暗くしています。
「**Blendable Location**」が **Before Translucency**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/0d8023ca-efcc-4f63-60d7-e17ea720c7c5.png)

「**Blendable Location**」が **Before Tonemapping**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/93f58507-4d79-167e-f6a9-10c6dcb0c27b.png)

前者 **Before Translucency** の際は、縁に DOF が掛かってボケているのに対し、
後者 **Before Tonemapping** の際は、縁がパッキリ切れて表示されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/3f8393e9-9298-67a0-03ba-4811c0279b81.png)
前者 **Before Translucency** は **(3)Post Process Material** を描いて色を暗くしてから、**(4)DOF** を掛けるので縁もボケます。
後者 **Before Tonemapping** は **(4)DOF** でボケた後に、**Post Process Material** で色を暗くしています。

この際、SceneTexture 系はもっと前の描画パスの情報になります。
<font color="OrangeRed">**なので、DOF でボケる前の情報なので、これを使用するとパッキリ切れてしまいます。**</font>


# 結局どうするのがいいの？
「プロジェクト毎に考えて対応する必要がある」とよくよく言われるのがこの辺りの問題です。

そもそも Translucency を使うことが少ないプロジェクトならそこまで考慮しなくてもいいかもしれない。
DOF を使わなければ考慮に入れなくていい。
カットシーンだけで DOF 使うのなら、カメラや演出、最悪問題が出るオブジェクトを非表示にして対処できるかも。
問題があった場合に Distortion を無くしてしまってもいいか。

などなど……
チーム内でアート、エンジニア、デザイナーで対応する方向を詰める必要があるかなぁと思います。

UE4のお仕事もやったりしてましたけど、毎度頭を悩ませます。
みんなどうしてるんでしょうね。