メインコンテンツまでスキップ

シャドウ

シャドウはシーン内のオブジェクトを接地させ、奥行きやオブジェクト同士の空間的な関係を伝えることで、リアリズムと視覚的な完成度を高めます。

PlayCanvas は、シャドウマッピングと呼ばれる技術を使用してリアルタイムの動的シャドウをレンダリングします。これはすべてのライトタイプでサポートされ、デスクトップからモバイルまですべてのプラットフォームで動作します。このページでは、シャドウを有効にする方法、どのオブジェクトがシャドウをキャスト/受信するかの選択、シャドウタイプの選択、そして品質の調整方法について説明します。

シャドウの有効化

デフォルトでは、PlayCanvasではシャドウキャストは無効になっているため、自分で明示的に有効にする必要があります。まず、シーンでシャドウをキャストするライトを特定します。各ライトには「Cast Shadows」というオプションがあります。次に、どのグラフィカルオブジェクトがシャドウをキャストおよび受信するかを選択します。デフォルトでは、すべての render および model コンポーネントがシャドウをキャストおよび受信し、エンティティごとに切り替えることができます。

// ライトのシャドウキャストを有効にする
entity.light.castShadows = true;

// メッシュエンティティはデフォルトでシャドウをキャスト・受信します(render または model コンポーネント)。
// 必要に応じてエンティティごとに切り替えます
meshEntity.render.castShadows = true;
meshEntity.render.receiveShadows = true;

シャドウタイプ

ライトのシャドウをフィルタリングする技術(エッジの柔らかさ、品質、パフォーマンスのトレードオフ)は、ライトごとに選択します。PlayCanvas には3つのフィルタリング技術があります。

注記

クラスタードライティングが有効な場合(デフォルト)、ライトごとのシャドウタイプは Directional ライトにのみ適用されます。Spot ライトと Omni ライトはすべて、シーンのライティング設定で指定する単一のシーン全体のシャドウタイプ(PCF のみ)を共有します。

PCF (Percentage-Closer Filtering)

シャドウのアウトラインをペナンブラと呼びます。これは暗から明への遷移で、シャドウに柔らかいエッジを与えます。デフォルトの技術である PCF は、シャドウマップから複数の局所的なサンプルを読み込んで平均し、このエッジを一定量だけ柔らかくします。

Hard vs soft shadows

カーネルサイズがトレードオフを決めます。1×1 は最も硬いエッジ、3×3 はデフォルト、5×5 は最も柔らかいエッジになります。カーネルが大きいほど多くのテクセルをサンプリングし、GPU コストが高くなります。

シャドウタイプを PCF のいずれかに設定します。

// SHADOW_PCF1_32F | SHADOW_PCF3_32F (default) | SHADOW_PCF5_32F
entity.light.shadowType = pc.SHADOW_PCF5_32F;

VSM (Variance Shadow Maps)

バリアンスシャドウマップは、事前にブラーをかけられる統計的な深度情報を格納し、Directional ライトのシャドウのような広い範囲に適した滑らかでソフトなエッジを生成します。16 ビットと 32 ビットの精度バリアントがあり(後者がより高精度)、一部のシーンではライトブリーディングのアーティファクトが発生することがあります。

注記

VSM は Directional ライトと、クラスタードでない Spot ライトでのみ利用できます。

シャドウタイプを VSM に設定して調整します。

entity.light.shadowType = pc.SHADOW_VSM_16F;

// 任意の調整
entity.light.vsmBlurSize = 11; // ブラーのカーネルサイズ、1-25
entity.light.vsmBlurMode = pc.BLUR_GAUSSIAN; // または pc.BLUR_BOX(より低コスト)
entity.light.vsmBias = 0.0025; // シャドウアクネを軽減、0-1

PCSS (Percentage-Closer Soft Shadows)

PCF は一定の幅のソフトなエッジを生成します。しかし実際のシャドウは、2つのオブジェクトが接する部分では鮮明で、キャスターがシャドウを受ける面から離れるにつれて柔らかくなります。PCSS はこのコンタクトハードニングの挙動を再現し、シャドウのキャスターとレシーバー間の距離に基づいてペナンブラの幅を変化させます。

Soft shadows using PCSS

注記

PCSS は Directional ライトでのみ利用できます。

また、PCSS は、デバイスが浮動小数点テクスチャへのレンダリングと線形フィルタリングをサポートしている必要があります。これは最新のデスクトップ GPU では広くサポートされていますが、特に古い、または低スペックのモバイルデバイスでは、必ずしも利用できるとは限りません。サポートされていない場合、ライトは自動的に PCF にフォールバックするため、PCSS は常に安全に有効化できます。

シャドウタイプを PCSS に設定し、微調整します。

entity.light.shadowType = pc.SHADOW_PCSS_32F;

// 任意の微調整
entity.light.penumbraSize = 2; // ペナンブラの全体的なサイズ(柔らかさ)
entity.light.penumbraFalloff = 1; // 距離に応じて柔らかさが増す速さ、1 以上
entity.light.shadowSamples = 16; // フィルタサンプル数。多いほど滑らかでコスト増
entity.light.shadowBlockerSamples = 16; // 0 でコンタクトハードニングを無効化

シャドウの調整

PlayCanvasが使用するシャドウマッピング技術には有限の解像度しかありません。そのため、できるだけ見栄え良くするために、いくつかの値を調整する必要があります。以下の各プロパティは、EditorのLightコンポーネントのUIで設定するか、コードでライトコンポーネント(entity.light.*)に設定できます。

シャドウ解像度

すべてのライトは、シャドウマップを介してシャドウをキャストします。このシャドウマップ(light.shadowResolution)は、16x16 から 4096x4096 までの解像度になり、この値もLightコンポーネントのインターフェイスで設定されます。解像度が高いほど、シャドウがより鮮明になります。ただし、解像度が高いほど、シャドウをレンダリングするために負荷がかかり、フレームレートに影響を与える可能性があります。

シャドウ距離

シャドウ距離(light.shadowDistance)は、ビューポイントから遠くの方向性ライトのシャドウがレンダリングされなくなる距離です。この値が小さいほど、シャドウがより鮮明になります。問題は、ビューポイントがシーンを移動すると、見る人が影が突然現れるのを見ることができるということです。したがって、この値は、プレイヤーが遠くまで見ることができる距離と一般的にどちらが良いかに基づいてバランスを取る必要があります。

シャドウカスケード

大面積の方向性シャドウを使用すると、しばしばエイリアシングが発生し、カメラの近くの影が低解像度になることがあります。単一のシャドウマップで影をキャプチャするには、この問題を改善するために非常に高い解像度が必要ですが、実用的ではありません。

シャドウカスケードは、この問題を解決するために、ビュー方向に沿ってカメラビューフラスタムを分割し、各分割に別個のシャドウマップを使用する方法です。これにより、近くのオブジェクトには1つのシャドウマップが割り当てられ、遠くのオブジェクトは別のシャドウマップがキャプチャされます。オプションで、その間にさらにシャドウマップを追加します。

ただし、シャドウキャスティングメッシュの数に影響を与えるため、シャドウカスケードの数はパフォーマンスに影響を与えます。

カスケード数(light.numCascades)は、ビューフラスタムの分割数を表し、1、2、3、4の値が設定できます。既定値の1は、単一のシャドウマップを表します。

単一のシャドウカスケードを示すスクリーンショット。

One cascade

4つのシャドウカスケードを示すスクリーンショット。

Four cascades

個々のシャドウカスケードのカメラフラスタムのサブディビジョンの分布(light.cascadeDistribution)。0から1の値を指定できます。値0は線形分布を表し、値1は対数分布を表します。ビジュアル的には、値が高いほど、前景オブジェクトにシャドウマップ解像度がより多く割り当てられ、値が低いほど、遠くのオブジェクトに割り当てられます。

シャドウ強度

このライトによってキャストされる、1を完全な強度のシャドウ、0をシャドウのないものとするシャドウの強度(light.shadowIntensity)。

Shadow Intensity

シャドウアーティファクトの解消

シャドウマッピングは、非常に醜い外観のレンダリングアーティファクトが発生する可能性があります。以下のプロパティは、それらの解消に役立ちます。

シャドウバイアス

影の帯や、期待しない場所に斑点状のパッチがある場合は、シャドウバイアス(light.shadowBias)を調整して問題を解決する必要があります。

法線オフセットバイアス

「影の吹き出物」は大きな問題ですが、シャドウバイアスを使用することで効果的に解決できます。残念ながら、これにより常に「ピーターパン」現象が発生します。それは、影によってオブジェクトが空中に浮いているように見える現象です。

法線オフセットバイアス(light.normalOffsetBias)は、この問題を解決します。深度バイアスを使用するだけでなく、シャドウマップルックアップに使用されるUV座標をわずかに調整することで、シャドウの吹き出物とピーターパンを回避できます。フラグメントの位置は、そのジオメトリの法線に沿ってオフセットされます。この「法線オフセット」技術は、定数シャドウバイアスのみを使用するアプローチよりもはるかに優れた結果をもたらします。

パフォーマンスに関する考慮事項

影を使用すると、パフォーマンスに以下のような影響があります:

  • 指向性またはスポットライトを落とすそれぞれの影のために、すべてのフレームで一度シーンをシャドウマップにレンダリングする必要があります。ポイントライトの場合はシーンがライトごとに6回レンダリングされるので(シャドウマップが6面のキューブマップとして保存される)、負荷が大きくなります。シャドウマップの中にシーンをレンダリングすると、CPUとGPUの両方に負荷を加えます。
  • シャドウマップの解像度を上げるとより鮮明な影を生成しますが、GPUはより多くのシャドウマップピクセルを埋める必要があり、フレームレートに影響を与える可能性があります。
  • シャドウタイプはコストに影響します。大きな PCF カーネル、VSM のブラー、特に PCSS(ピクセルごとに多数のサンプルを取得)は、ハードな単一サンプルのシャドウよりも GPU 負荷が高くなります。
  • Directional ライトでは、シャドウカスケードを追加するごとに、シャドウキャスターが複数のシャドウマップにレンダリングされる場合があり、コストが増加します。
  • 影が環境の静的な部分から発生している場合は、ライトマップを使用してテクスチャに影をbakeすることを検討してください。