[UE4]Lightmassで挙動が変わるマテリアルノードたち

UE4にはシーンを美しくしたい、軽くしたいという時
その要望を叶えてくれる**Lightmass**と呼ばれるライトマップビルドシステムがあります。
https://docs.unrealengine.com/ja/RenderingAndGraphics/Lightmass/index.html
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/1a43eea7-7fb4-3924-eee6-17af4d89e480.png)

背景などをクォリティアップする際、皆様このLightmassにとてもとてもお世話になるかと思うのですが、
先日このような疑問がツイッターに投稿されました。
https://twitter.com/kurosaurus/status/1332297754048008192?s=20
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/c884da11-6c3d-e2b8-affd-48405e87914d.png)

**はい、僕も気になります。**
というわけで、上記ツイートにはすでにお答えさせて頂いてるのですが
今回はさらにもう少しその詳細を書かせて頂こうかと思います。
（確認環境はUE4.26.0です。）


##ということで答えから
これらが**Lightmassで挙動が変わるマテリアルノードたち**です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/769e8fe6-fab3-e812-fccc-6fe729dfc262.png)
これらのノードは、ライトビルドの際に変な値が入らないように、
**固定値が設定されたり挙動しなくなったりします。**
（例えばCameraVectorノードはライトビルド時のカメラってなに…？となるので固定値が入るようになってるのかなと思います。）

ちなみにそれぞれのノードに入る固定値は以下です。
（重要そうなノードを太字にしています。）

| ノード名 | 値 |
|:------------:|:------------:|
| ParticleRelativeTime |　0 |
| ParticleMotionBlurFade |　1 |
| ParticleRandom |　0 |
| ParticleDirection |　(0,0,0) |
| ParticleSpeed |　0 |
| ParticleSize |　(0,0) |
| **WorldPosition** |　**(0,0,0)** |
| **ObjectPosition** |　**(0,0,0)** |
| **ObjectRadius** |　**500** |
| **ObjectBounds** |　**(0,0,0)** |
| PreSkinnedLocalBounds |　(0,0,0) |
| DistanceCullFade |　1 |
| **ActorPosition** |　**(0,0,0)** |
| **CameraVector** |　**(0,0,1)** |
| LightVector |　(1,0,0) |
| ReflectionVector |　(0,0,-1) |
| ReflectionAboutCustomWorldNormal |　(0,0,-1) |
| **VertexColor** |　**(1,1,1,1)** |
| PreSkinVertexOffset |　(0,0,0) |
| PostSkinVertexOffset |　(0,0,0) |
| PreSkinnedPosition |　(0,0,0) |
| PreSkinnedNormal |　(0,0,1) |
| **Time** |　**0** |
| DecalLifetimeOpacity |　0 |

また、これらはどこで設定されているかと言うと、
**Engine\Source\Editor\UnrealEd\Private\Lightmass\LightmassRender.cpp**にて、
各ノードがoverrideされております。
実際にソースを確認したい方はこちらをご確認頂けましたら幸いです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/0838f60e-8227-64ff-4c6f-01114390cf7c.png)
（実際には上記以外にももうちょっと多くのノードの挙動が変わるのですが、今回は明示的にOverrideされているものだけご紹介ということで……）

##陥りがちな罠
さて、これらの仕様、ライトビルドの際上記のノードを使わず、
シンプルなマテリアルでビルドする限りは特に問題になりません。

しかし例えば以下のシーン。
ベクター値で直接カラー設定したものは適切にGIがベイクされていますが……、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/9beee770-d5d5-e6ff-ad60-89ab643d14ed.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/d8d0a2da-01ed-7b43-a1f7-d363c5aabe16.png)

**VertexColorノード**でカラー指定すると、
**(1,1,1,1)の真っ白の固定値**にされてしまう為、GIが正しくベイクされなくなってしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/0d0c5eeb-cac8-008f-cf26-641e577d2dec.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/7ce9beee-28e7-35db-28d8-7d0695bdef09.png)
Vertex Colorは直接色を設定するだけでなく、
以下のような**レイヤードマテリアルなどでも使用される事が多い**と思いますので気をつける必要がありますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/292b8365-f1e9-b05c-4e41-037425814a6f.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/960d18c9-0804-9d6c-83a9-ddbb5f22b71f.png)
また、テクスチャをシームレスに貼る為に**WorldPositionノード**などを使用している場合も要注意です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/3853891b-774f-33b0-7bab-10763565ad2d.png)
WorldPositionは**(0,0,0)の固定値**になる為、
ライトビルド時にテクスチャサンプルが正しく行われなくなってしまいます。
（同じ理由でWorld Aligned系のノードも正しく挙動しません。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/a4a22c7e-794e-955a-9e49-558bbd2d7435.png)
質問にもあった**Timeノード**も気になりますね。
こちらも**0固定**ですので、時間によって色が大きく変わるものは危険です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/9eac6c62-010a-5357-3f62-52db7f2ef2b4.png)
他にもFresnelやParallax、BumpOffsetなどで使用されている**CameraVectorノード**、こちらは**(0,0,1)固定**です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/ace9a5f3-0a0e-0492-8812-c93a188c4256.png)
以前別の記事を書かせて頂いた汎用性の高い**ObjectPositionノード**と**ActorPositionノード**、
こちらは**(0,0,0)固定**。
https://qiita.com/EGJ-Osamu_Saito/items/502c4f8adc55737072d4
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/ceb19c61-c063-9286-cf2d-258d19f5a1e6.png)
ActorPositionノードなどは汎用性の高さから、
以下のような感じで位置に応じて色を変えるなどしたりするかと思うのですが、
**GIが適切にベイクされなくなる点**には気をつける必要がありそうです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/48efee47-7a19-a80b-01c8-25d8124315fa.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/6fb36799-30c3-2497-5b38-a0dcfecf4705.png)
さらには**ObjectBoundsノード**は**(0,0,0)**なのに
**ObjectRadiusノード**は**500**と謎の値が入っているのも要注意ですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/912dd89c-bb51-5d1f-6c62-54bc19fc802d.png)
##対応方法
という感じで、UE4はライトビルド時思いも寄らないマテリアルの結果になってしまうことがあります。
しかしご安心下さい。UE4は対応方法もご提供しております。

それが**LightmassReplaceノード**です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/7c4f6942-a01a-b1ba-557f-9cf18e2acf1d.png)
こちらを使うと、**Lightmassの時にだけ使用されるようにマテリアルの処理を分岐することが可能です。**
https://docs.unrealengine.com/ja/RenderingAndGraphics/Materials/ExpressionReference/Utility/index.html
https://christinayan01.jp/architecture/archives/7662
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/e13ee90f-e068-ea11-03a2-ba52ac0e9954.png)
これまでに挙げた**Lightmassで挙動が変わるマテリアルノードたち**を使って複雑なマテリアルを作っている場合は、
上画像のようにLightmassReplaceノードを使用して適宜処理を分けて頂けたらと思います。
（GIの効きが悪いからちょっと色をブーストする、なんてことも可能です。）
##補足
ちなみのこれらの挙動、
UE4.26よりベータ機能として提供されている**GPULightmassにおいては大きく改善されております。**
![gpul.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/e8d4e4d8-394d-7669-f34e-435b1f3e66bb.gif)
以下のRoadmapにもあるように、GPULightmassはレイトレをベースにライトビルドを行う為、
**VertexColorなどCPULightmassで無視されてきたノードの多くが問題なく挙動します。**
（全てではありません。Timeノードとかは変わらず0固定です。）
https://portal.productboard.com/epicgames/1-unreal-engine-public-roadmap/c/192-gpu-lightmass-beta
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/0f20bc6f-4544-568e-179e-4ac6a9ffeb4a.png)


つまりどういうことかというと、CPULightmassで問題となっていた、
**VertexColorノード**や、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/a6b41ce4-8f0d-edd2-71d4-d5a5b21f413c.png)
**WorldPositionノード**、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/c51a724b-0348-f208-f6a3-3d46c5093696.png)
**ObjectPositionノード**や**ActorPositionノード**なども、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/9c2772b3-0119-8676-5d8f-237d7ba10092.png)
**全て問題なく挙動します。素晴らしいですね！**


詳細が気になる方は、GPULightmassで使用されているシェーダーは、
以下の辺りにありますので、こちらをご確認頂けたらと思います。
**Engine\Plugins\Experimental\GPULightmass\Shaders**


また、GPULightmassで使用されているシェーダーには以下のようなコメントもあり、
将来的にはワールドポジションオフセットもサポートされるかもしれません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/bf8b384c-54e1-2419-a4e6-ba1a66368f1f.png)
設置感改善やバリエーション出し、シャドウリーク回避の為に頂点オフセットしたいけど、CPULightmassで正しくベイクできない……というオブジェクトもGPULightmassでは問題なくなるかもしれませんね。
（ちなみにCPULightmassではベイク時にLOD0が使われる仕様を利用して、ベイク軽量化や、シャドウリーク回避を行う若干ハッキーな方法があります。）
https://www2.slideshare.net/EpicGamesJapan/ue4-139190804
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/7d02a2a6-dc74-2e6e-8d7a-638b4b3ebd5c.png)
最後に、一点気をつけるべき点としまして、
**GPULightmassではLightmassReplaceノードは使用できません。**
もしGPULightmassでベイク結果を調整したい場合は**RayTracingQualitySwitchReplaceノード**を使う必要があります。
（このノードはライトベイク時だけではなく通常のレイトレ描画にも影響しますのでご注意下さい。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/bccadb72-bb6d-e899-199f-573da410fbcd.png)
現時点では上記の状況に加え、CPULightmassで使用できていた一部のパラメーターがGPULightmassでは効かないなど、
**CPULightmassとGPULightmassは全く同一の結果とはならない**点を気をつける必要があるのですが、
（DiffuseBoostやUse Emissive for Static Lightingなどが挙動しません）
速度面や利便性という点でGPULightmassは非常に便利かと思いますので、
ケースバイケースで運用して頂けましたら幸いです。
<br>
それでは皆様楽しいLightmassライフを！