検証UE4: 4.27.2
まちがってたらごめんなさい。
はじめに
メッシュへの距離情報からShadowを落とすDistance Field Shadowについての話になります。
ゲームだと遠方の影をCascade ShadowからDistance Field Shadowにして負荷軽減したり、精度を上げたりするような時に使ってるかと思います。
ただ、このDistance Field Shadowでは落とせないメッシュがあったりします。
その場合、Cascade ShadowとDistance Field Shadowの境目で影が切れてしまい格好悪い感じになってしまいます。
なんとかしたい。
- 参考資料
- ディスタンス フィールド シャドウを使用する - 公式ドキュメント
- [UE4] Shadow Rendering(影描画)機能入門 - Qiita EGJ-Yutaro_Sawada(Epic Games Japan)
まとめ
(いつも長いと言われるので先に)
- Distance Field Shadow で落とせるのはStaticMeshのみ。
- ステーショナリーライトのInset Shadow For Movable ObjectsでムーバブルなMeshの影を落とせる
- メッシュ設定のInset Shadowでメッシュ個別に影を落とせる
- ムーバブルなライトならどのメッシュからも影を落とせる
処理方法 | StaticMesh スタティック |
StaticMesh ムーバブル |
SkeletalMesh | SplineMesh スタティック |
SplineMesh ムーバブル |
---|---|---|---|---|---|
Distance Field Shadow | ○ | ○ | × | × | × |
Inset Shadow For Movable Objects (ステーショナリーライトのみ) |
× | ○ | ○ | × | ○ |
メッシュのInset Shadow +ステーショナリーライト |
× | ○ | ○ | × | ○ |
メッシュのInset Shadow +ムーバブルライト |
○ | ○ | ○ | ○ | ○ |
スタティックなSplineMeshが厳しい。背景配置で多様するだろうし……
メモリが許せば全部StaticMesh化するのが良いのだろうけど、流石に。
何か出来ないかと試した結果で #Distance Fieldだけを生成したい だけど、SplineMeshに汎用近似メッシュ合わせるのはすこし厳しいか……
Distance Field Shadowで落とせない影
Distance Field Shadowですが、SkeletalMeshとSplineMeshは影を落とせません。
と言いますのも、SkeletalMeshとSplineMeshはDistance Field Shadow描画の元となるDistance Fieldが生成できません。
こちらがDistance Field。SkeletalMeshとSplineMeshからは生成できません。
Distance Field自体が変形できない為、変形するメッシュには追従できず反映されません。
とはいえ何も出てないのは格好悪いのでなんとかしたい……
ステーショナリーライト:Inset Shadow For Movable Objects
ステーショナリーなライトでのみ使用可能です。
この機能は、「ムーバブルなオブジェクトはInset Shadowを利用して影を落とす」形になります。
Inset Shadowとは?となりますが、これはオブジェクト個別にShadow Mapを生成して影を落とす事になります。
詳しくは下記Pre Shadow項目に詳しく書かれています。参照してください。
[UE4] Shadow Rendering(影描画)機能入門-PreShadow項目
ライトの可動性がステーショナリーな場合は、Inset Shadow For Movable Objectsがデフォルトで有効になっています。
今回の場合、ムーバブルなオブジェクトがこのように一つずつShadow Map生成されています。
その分、ムーバブルなオブジェクトが増えれば負荷が増えることが想定されます。
逆にデフォルトでONになっているので、遠景のムーバブルは影要らない!の時はOFFにするいい思います。
メッシュのDynamic Inset Shadow
前述のInset Shadow For Movable Objectsのメッシュ側のフラグになります。
Inset Shadow For Movable Objectsはライト側の設定で、ONにすると全てのムーバブルなメッシュに対して処理を行うのですが、こちらはメッシュ側の設定なので、このメッシュだけInset Shadowを使う!等が出来ます。
また、違いとして下記のようになっているようです。
- ステーショナリーなライトの場合は、ムーバブルなメッシュのみInset Shadowが使用可能
- ムーバブルなライトの場合は、スタティックなメッシュでもムーバブルなメッシュでもInset Shadowが使用可能
こちらも一つずつShadow Mapを生成しますので、多数をONにすると負荷が増える事が想定されます。
目立つメッシュや、カットシーン中はONにするとかでしょうか。
Distance Fieldだけを生成したい
頑張ったけどいい感じには出来なかった。
人型には難しい。負荷的にはちょっとだけエンジン弄る必要ありそう。
メモとして残しておきます。
Inset Shadowを使わず、Distance Field Shadowの仕組みを流用してそのまま影が出せないか、という所でDistance Fieldのみを生成する方法が無いか試してみました。
特に車とか乗り物はタイヤを動かすためだけにSkeletalMeshにしている事があり、その為にDistance Field Shadowが使えず勿体ない感じがします
今回はSkeletalMeshComponentの位置に合わせて、近似的なStaticMeshを使用して代用する方法を試してみました。
結果はこちら。カメラが離れた時がDistance Fieldです。
(ちょっと近似的なメッシュを作らず、横着してCubeを使用しました。きっちり形合わせたい場合は車の形そのままのStaticMeshを用いれば良いかなと……)
やった手順
- DistanceFieldだけ生成したいStaticMeshを配置。今回はCubeで代用
- MeshComponentのオプション設定
- 現状だとカメラが近い所のCascade Shadow時にも描画されてしまうのでマテリアルを差し替えます
- これで、見た目上はDistance Fieldにのみ影響を与えるメッシュ配置になります。
問題として、
モーションには追従しないので、人形状等は難しいかも。
(やるとしたらCapsule Shadowみたいに各ボーンにメッシュくっつけて追従させるとかしか……)
DistanceField用Meshが元メッシュの形状からはみ出ると、元のメッシュにも影を落としてしまうので難しい。
※また、この方法だと画面には表示はされないもののCascade Shadow範囲内に入った際に、このメッシュもCascade描画が走ってしまう問題がある。
低コストマテリアルとはいえ負荷に。Inset Shadowとどっちが負荷的に良い?
この辺りも回避するにはエンジン改造するしかないかも。以下エンジンコード側の話メモ。
CastsDynamicShadowがONでないとDistanceFieldに積まれない。
けどCastsDynamicShadowがONになるとCascade Shadowにも積まれてしまう。
何かDistance Fieldのみ積む用フラグを追加して、FDistanceFieldSceneData::AddPrimitive 辺りでCastsDynamicShadow無視して積めばいけるかも。
未検証。