
シャドウ(影)は、3Dシーンに実在感や説得力をもたらす重要なディテールのひとつですが、同時に破綻が目立ちやすい要素でもあります。今回のアップデートにより、太陽光のシャドウがより安定してクリーンになり、調整もはるかに簡単になりました。また、スポットライト、ポイントライト、エリアライトにも同様の改善が適用されています。
概要:
- 安定したカスケード。 カメラの移動や回転時に、ディレクショナルライトのシャドウがちらつかなくなりました。
- よりスマートなバイアス。 シャドウマップのテクセル単位で測定される一つの設定が、最も近いカスケードから最も遠いカスケードまで機能します。
- シームレスなライト。 ポイントライトのキューブの継ぎ目がなくなり、スポットライト、ポイントライト、エリアライトが新しいバイアスモデルを共有します。
- さらなる制御。 1~4つのカスケード、その分割方法とフィッティング方法、遠方のカスケードの更新頻度を選択できます。
- より優れたデバッグ。 各カスケードとテクセル密度をビューポートで直接確認できます。
この記事の内容
なぜ影が重要なのか
シーンから影を取り除くと、すべてが浮いているように見えます。オブジェクトは地面とのつながりを失い、奥行きが分かりにくくなり、ライティングは平坦に見えます。適切な影は、物の位置、大きさ、そして光がどこから来ているのかを教えてくれます。
質の悪い影も同様に目立ちます。カメラの動きに合わせて這うようなエッジ、表面に現れる縞模様、あるいは影がそれを落とすオブジェクトから剥がれてしまう現象は、すべて即座に没入感を損ないます。今回のリリースは、まさにこれを解決するものです。
リアルタイムシャドウはどのように機能するのか?
現実の影は光が遮られることで生じますが、リアルタイムレンダラーは光を追跡しません。代わりに、シャドウマップと呼ばれる、より低コストで非常に効果的なトリックを使用します。
- 光源から見る。 光源の視点からシーンをレンダリングしますが、各ピクセルについて最も近いサーフェスまでの距離のみを保存します。その結果がシャドウマップです。
- カメラから見る。 画面上の各ピクセルについて、光源の視点から見た位置を計算し、その距離をシャドウマップに記録されたものと比較します。
- 判定する。 光源により近いものが記録されていた場合、そのピクセルは影の中にあります。そうでなければ、光が当たっています。
問題は、シャドウマップが固定解像度のテクスチャであることです。光源から撮影されたシーンの低解像度写真と考えてください。ほぼすべてのシャドウ技術は、この限られた解像度を最大限に活用する方法なのです。
レイトレーシングやパストレーシングによる影については?
シャドウマップは近似であるため、なぜ単純に光を追跡しないのかと問うのは当然です。ハードウェアレイトレーシング対応のGPUではそれが可能です。各可視点から光源に向けてレイを飛ばし、何かが遮ればその点は影になります。テクスチャ解像度の限界がないため、ブロックノイズ、シャドウアクネ、ピーターパン現象は発生せず、ソフトシャドウも正確に得られます。パストレーシングはさらに一歩進み、シーン内で反射する多数のランダムな光の経路を追跡するため、シャドウ、反射、間接照明がすべて同じプロセスから生成されます。Evergineのパストレーサーのサンプルでその様子をご確認いただけます。
その代償はパフォーマンスです。クリーンな画像を得るには、フレームごとにピクセルあたり数本のレイが必要で、通常はその後デノイザーが適用されます。シーンには、オブジェクトの移動に応じて再構築が必要な加速構造が必要です。さらに、レイはあらゆる方向に散乱するため、三角形をテクスチャにラスタライズするよりもGPUメモリに大きな負荷がかかります。ハイエンドのデスクトップGPUでさえレイの使用は慎重に予算管理されており、ほとんどのスマートフォン、タブレット、ローエンドデバイスにはハードウェアレイトレーシングが全く搭載されていません。
これが、シャドウマップが依然としてリアルタイムシャドウの主力である理由です。低コストで予測可能であり、事実上あらゆるデバイスで動作します。レイトレーシングはハードウェアが許す場合の優れた選択肢ですが、それ以外のすべての環境でシーンを動かし続けるのがシャドウマップであり、だからこそ我々はシャドウマップへの投資を続けています。
太陽の問題とカスケード
ディレクショナルライトは太陽の代わりとなり、太陽はすべてを照らします。単一のシャドウマップで可視世界全体をカバーしようとすると、数百メートルに引き伸ばされたテクスチャは、ディテールが最も重要なプレイヤーの目前でさえブロック状の影を生み出します。
古典的な解決策はカスケードシャドウマップです。ビューをカメラからの距離に応じてスライスに分割します。手前の小さなスライス、その背後により大きなスライス、という具合です。各スライスが独自のシャドウマップを持つため、近くの影はシャープに、遠くの影は粗くなります。遠くのものは画面上で小さいため、ほとんど気になりません。
Evergineはすでにカスケードを使用していました。今回のリリースは、その動作を改善することに焦点を当てています。
従来のアプローチが苦戦していた点
以下の3つの問題が繰り返し発生していました。
- シマリング。 各カスケードはカメラの向きに基づいて配置されていたため、カメラが回転するとシャドウマップのグリッドがワールド上をスライドし、影のエッジが這い回り、ちらつきました。
- シャドウアクネと浮遊する影。 シャドウマップはサンプルのグリッドであるため、サーフェスが誤って自身に影を落とし、縞模様(シャドウアクネ)が現れることがあります。通常の対処法は小さなバイアスですが、単一の固定値ではすべてのカスケードに対応できません。小さすぎるとグレージング角(浅い角度)で縞模様が残り、大きすぎると影がキャスターから離れてしまい(ピーターパン現象)、特に遠方のカスケードで顕著になります。
- チューニングの余地が少ない。 カスケードの数は4つに固定されており、その配分方法に対する制御も限られていました。
新機能
シマリングが解消されたカスケード
シャドウ空間は、カメラの向きではなく、光源の方向のみに依存するようになりました。各カスケードはシャドウマップのテクセルグリッドにスナップされ、そのサイズは約2%の小さなステップでのみ変化します。その結果、カメラの移動や回転によって、ワールドのどの部分をどのテクセルがカバーするかが変わらなくなり、シマリングは解消されました。
シーンを理解するバイアス
バイアスがワールド空間で適用され、シャドウマップのテクセル単位で計測されるようになりました。2つの新しいプロパティShadowDepthBiasとShadowNormalBiasは、各カスケードのテクセルサイズとシャドウフィルターのソフトネスに応じて自動的にスケールします。単一の設定で、最も近いカスケードから最も遠いカスケードまで適切に動作するようになり、グレージング角でのシャドウアクネの縞模様や遠方での浮遊する影が解消されます。
スポットライト、ポイントライト、エリアライト
テクセルベースのバイアスモデルは太陽光に限定されません。スポットライト、ポイントライト、エリアライトでも使用されるようになり、ShadowDepthBiasとShadowNormalBiasはすべてのライトタイプで同じ意味を持ちます。併せて2つの問題を修正しました:
- ライトの投影軸から背を向けたサーフェスに発生するシャドウアクネのリング。
- ポイントライトの可視シーム。 ポイントライトはキューブの各面に1枚ずつ、計6枚のシャドウマップを使用しますが、以前のフィルターはエッジに沿って不正なデータを読み取っていました。各面が90度よりわずかに広く、8テクセルのマージンを持ってレンダリングされるようになり、隣接する面が重なりシームが消えます。この修正はポイントライト固有のものです。
調整可能なカスケード
ディレクショナルライトで、品質とパフォーマンスのトレードオフを調整できるようになりました:
- カスケード数: 1から4まで。各ライトは必要なシャドウマップのみを割り当てます。
- 分割モード: 自動 は、
GammaDistributionで制御される対数分布と均一分布をブレンドします。手動 では、各カスケードの終端を自由に決定できます。 - フィットモード: 安定 (デフォルト) は各カスケードをそのスライス周辺の球にフィットさせるため、テクセルサイズが変わりません。タイト は代わりにボックスにフィットさせ、テクセルサイズが約20%小さくなりますが、カメラ回転時に多少のちらつきが生じます。
- 選択モード: 各ピクセルのカスケードをビューの深度で選択するか、そのピクセルを含む最初の (最もシャープな) カスケードを選択することで、より多くのピクセルが高解像度マップを使用します。
- カスケードブレンドとシャドウフェード: 隣接するカスケードを相互にブレンドし、シャドウを最大シャドウ距離の手前で切り取らずに滑らかにフェードアウトできます。
- 遠方カスケードの更新間隔: 遠方のシャドウはゆっくりと変化するため、遠方カスケードをNフレームごとに再レンダリングできます。カメラとライトが許容範囲内にある間、エンジンはキャッシュされたマップを保持し、シャドウパスのコストを削減します。
注意: 1つのライトが複数のカメラでレンダリングされる場合、更新間隔は効果がありません。
デバッグ機能の改善
ライトのデバッグモードで、各カスケード (およびポイントライトの各キューブ面) の色に加え、8x8シャドウマップテクセルのチェッカーボードが表示されるようになり、画面上のシャドウ密度を正確に確認できます。スポットライトにも専用のDebugModeが追加されました。
関連する問題も修正しました: カスケード分割距離が正しい計算式を使用するようになり、ゼロのニアプレーンを持つ平行投影カメラで無効な分割が生成されなくなり、複数のシャドウキャストディレクショナルライトで複数のカメラをレンダリングしても、ライトが互いのシャドウマップを上書きしなくなりました。バックエンドは深度クランプを一貫して処理するため、カスケードの手前にあるオブジェクトがクリップされなくなりました。
違いを見る
スライダーをドラッグすると、同じシーンおよびカメラ位置における従来のシャドウシステムと新しいシャドウシステムを比較できます。
はじめに
すべての設定はエディターまたはコードから調整できます。以下の値は参考の開始点ですので、シーンに合わせて調整してください:
// Get the directional light of your sun entity
var sun = sunEntity.FindComponent<DirectionalLight>();
sun.IsShadowEnabled = true;
sun.ShadowDistance = 100; // How far from the camera shadows are rendered
sun.ShadowCascadeCount = 3; // Between 1 and 4
// Keep cascades stable, and fade shadows out smoothly
sun.CascadeFitMode = DirectionalLight.CascadeFitModes.Stable;
sun.ShadowFadeFraction = 0.1f;
sun.CascadeBlendFraction = 0.1f;
// Bias is measured in shadow map texels
sun.ShadowDepthBias = 1;
sun.ShadowNormalBias = 1;
これにより、3つの安定したカスケード、カスケード間のスムーズなブレンド、およびシャドウ距離での穏やかなフェードを備えた、影を落とす太陽光が有効になります。シャドウアクネが見られる場合はバイアスをわずかに上げ、影がキャスターから浮いて見える場合は下げてください。
以前のバージョンからのアップグレード
既存のプロジェクトに影響するいくつかの変更点があります:
ShadowBiasは廃止され、無視されます。ShadowDepthBiasとShadowNormalBiasを使用してください。これらはテクセル単位で計測されるため、古い値はそのまま引き継がれません。DirectionalLightShadow、PointLightShadow、SpotLightShadowを呼び出すカスタムシェーダーがある場合、それらはNoLの代わりにジオメトリック法線を受け取るようになりました。- カスタムシェーダーが
LightProperties.CascadeSplitsを読み取る場合、それがカスケード境界のfloat4になったことに注意してください。最初の値はシャドウの開始位置、次の3つは最初の3つのカスケードの終了位置です。
ぜひお試しいただき、ご意見をお聞かせください
より安定したクリーンなシャドウをシーンに与える準備はできましたか? Evergineをアップデートし、ディレクショナルライトのあるシーンを開いて新しいオプションをお試しください。
- ライトとシャドウの完全なリファレンスについては、Evergineドキュメントをご覧ください。
- Evergineサンプルで、実際のシーンでのライトとシャドウをご確認ください。
- 問題を発見されたり、アイデアをお持ちですか? Evergineフィードバックリポジトリでお知らせください。
皆様のご意見をお待ちしております。
