BLOGブログ

2023.01.25UE5UE/ Lighting

[UE5] UE5でWorld Position Offsetを使ったときに影が残る現象について

執筆バージョン: Unreal Engine 5.1

 

この記事ではUE5を触っていて、気になった影の残像が残る現象について2つ、取り上げたいと思います。
(すべての影の残像問題を取り上げているわけではありませんのでご了承ください)

1つ目はDistance Field Shadows、2つ目はVirtual Shadow Mapsです。

 

 

1.Distance Field Shadowsで起きた影の問題について

 

UE5.1でSkyLightをMovable、かつ、マテリアルのWorld Position Offsestでメッシュをもとの位置からオフセットしていると、
影が元のメッシュの位置に残ってしまう現象が発生しました。

 

 

UE4.27で同じ状況にしても、同様の現象にはなりません。

 

これはUE5.1ではデフォルトでGenerate Mesh Distance Fieldsが有効になっており、
かつ手動でLumenを無効化したためでした。

 

Mesh Distance Fieldsで生成されるメッシュは、World Position Offsestなどでの変形の前に生成されてしまいます。
ここで描かれているズレた影はDistance Field Ambient Occlusionです。
Distance Field Ambient OcclusionはMesh Distance Fieldsを参照しているため、メッシュの元の位置に影が残る状態になっています。

(Mesh Distance Fieldsは、ビューポートのShow > Visualize > Mesh Distance Fieldsから確認できます)

 

 

UE4.27で発生していなかった理由は、Mesh Distance Fieldsが有効にはなっていないためでした。

もちろん、UE4.27でも、Generate Mesh Distance Fieldsを有効にするとUE5.1と同じ現象が発生します。

 

 

対応としては以下などがあります。

 

 

・Lumenを有効にする

Lumenも仕組み自体はMesh Distance Fieldsを参照している部分もあるのですが、World Position Offsetなど、
Lumenのソフトウェアレイトレーシングに対応していないものは見た目に不都合が出ないようにしてくれているっぽいです。
(ScreenTraceで処理しているということですかね…?)

 

 

・Distance Field Shadowsを無効にする

アクターのDetails>Lighting>Affect Distance Field Lightingのチェックボックスを外すと、
設定したアクターはDistance Field Shadowsを使用しなくなるので、影のズレを修正することができます。

 

 

 

 

2.Virtual Shadow Mapsで起きた影の問題について

 

 

次はデフォルト設定のままのUE5.1でまたWorld Position Offsetを使って見ます。
今度は更に球体が動き続けるようにしてみます。


なんだか影が置いてかれてしまっています。この影はAOではなく、CastShadowです。

 

この現象の原因は前述のMesh Distance Fieldsではなく、
UE5の新機能、Virtual Shadow Mapsが原因です。

 

このシーンにはDirectional Lightが1つと、Skylightが1つあります。
UE5ではDirectional LightのCascade Shadowの部分がVirtual Shadow Mapsに置き換わっています。

 

Virtual Shadow Mapsでは、たくさんの詳細なオブジェクトに対して動的に影を落とす際の負荷の対策として、
「キャッシュ」を行っています。

 

近くは細かい、遠くは粗い「ページ」に分割して、どこのページの影のキャッシュを更新するかを判定しています。


(ビューポートのLit > Virtual Shadow Map > Virtual Page からどのように分割しているか見れます)

 

では実際にはどのページが更新されているのか見てみましょう。
ビューポートから Virtual Shadow Maps > Cached Page を選択します。
影の情報が更新されている部分が赤、更新せず、キャッシュを表示しているのが緑です。

すると動いている球体の周りのページは赤色で更新されてはいますが、
端の部分が緑、つまり更新されていません。
そのため、影が表示され続けてしまっていました。

 

 

対応としては以下などがあります。

 

 

・キャッシュしない

r.Shadow.Virtual.Cache 0

このコマンドでキャッシュをしない状態(常に更新し続ける状態)にすることができます。
このコマンドを実行した状態でCached Pageを見てみます。


全部赤色、全体が常に更新されていることがわかります。

もちろん更新し続けているので、影が残ることもありません。

ですがシーン全体でVirtual Shadow Mapsのメリットであるキャッシュを封じてしまっているので、負荷的にはよろしくありません…

 

 

・アクターのBounds Scaleを調整する

どうやらVirtual Shadow Mapsの更新範囲はアクターのBoundsを見ているようです。
スフィアの元のBoundsですと更新範囲は以下のようになります。

World Position Offsetで動く範囲に対して、Boundsが小さく、そのため更新されるページも小さくなっています。

アクターのBounds Scaleを3にしてみます。

更新される部分が広くなり、影が正しく描画されるようになりました!

 

LumenとVirtual Shadow Maps、ここでは取り上げていませんがNanite(+Mesh Distance Fields)は、お互いを補い合う関係にあります。
ですので、どれかをOFFにすると問題が発生する可能性があるため、設定をデフォルトから変更する際は気をつけたいですね。

新機能は弱点(動くメッシュに弱いなど)もありますが、これから色々改善が入ったりしていきますし、デフォルトになっていくものだろうと思いますので、
上手に付き合っていきたいですね!