Unityのユニバーサルレンダーパイプライン(URP)において、水面のフチを滑らかにぼかす表現(Soft Water)や、煙や霧が地面と交差する部分をふわっとなじませる表現(Soft Particles)、あるいは画面全体を霧で覆うフォグ効果などは、ゲームのグラフィックスのクオリティを底上げする定番の演出です。これらを実現するためには、カメラから不透明オブジェクトまでの距離を示す「深度(Depth)情報」が不可欠です。しかし、Shader Graphで「Scene Depth」ノードを使用したり、C#から「_CameraDepthTexture」を参照した際、深度値が全く取得できずに画面が真っ白(または真っ黒)になり、演出が不自然なハサミで切ったようなパキッとした見た目で静止してしまうバグに遭遇したことはないでしょうか。本記事では、URP環境における深度バッファ取得失敗の根本原因を、「カメラマンと定規」の例え話を交えて解説し、解決のための設定手順とトラブルシューティングを詳細に解説します。
1. 例え話で理解する:『測量定規を持たずに撮影に出たカメラマン』
この深度テクスチャが取得できない問題を直感的に理解するために、『風景写真を撮影するカメラマンと、距離を測定するアシスタント』の関係を例えに考えてみましょう。
あなたが映画の監督(開発者)で、カメラマン(URPの描画エンジン)に対して「水辺に浮かぶモヤ(半透明エフェクト)のシーン」の撮影を指示しました。監督は「モヤが地面とぶつかる境界線は、地面からの距離に応じてグラデーションをかけて馴染ませてほしい」と注文します。この注文を処理するためには、アシスタント(深度テクスチャ生成パス)が「カメラから地面までの正確な距離」を測量した記録用紙(Depth Texture)を用意する必要があります。
しかし、撮影当日、プロデューサー(プロジェクト設定)が「撮影のスピードアップと機材費の削減(パフォーマンス最適化)」のために、アシスタントに『距離を測る定規(Depth Texture生成オプション)』を持たせるのを勝手に禁止してしまいました。アシスタントは距離を測れないため、記録用紙は真っ白な白紙のままです。カメラマンは記録用紙が白紙なので、距離の差が判断できず、仕方なくモヤを地面にベタッと上書きして撮影し、結果としてモヤの端っこが地面に突き刺さったような不自然な仕上がり(パッキリとした交差線)になってしまいました。
これが、URPにおける『深度テクスチャ無効化バグ』の正体です。Unity URPは、処理負荷を削減するために、明示的に「深度情報を別途画像(テクスチャ)として保存してください」と設定しない限り、深度バッファをメモリ上に残さず即座に破棄してしまうのです。
2. 根本的な原因:URPにおける深度情報の自動破棄仕様
Built-in(従来のレガシー)パイプラインでは、シェーダーが深度情報を要求すると、Unityが裏で自動的に深度テクスチャの生成を有効化していました。しかし、パフォーマンスの最適化を最優先するURP(およびSRP全体)では、描画パイプラインの動作を開発者が厳密にコントロールします。
GPUは不透明なオブジェクトを描画する際、前後関係を正しく判定するために内部的に「Zバッファ(デプスバッファ)」を使用します。不透明オブジェクトの描画が完了した時点で、通常はこのZバッファは用済みとなり、ビデオメモリ(VRAM)の帯域を節約するためにGPUメモリから消去(クリア)されます。半透明エフェクトを描画するレンダーパス(Transparent Pass)が動き始めた時には、すでに背景の深度情報は物理的に消去されて存在しないため、シェーダーが「Scene Depth」を参照しようとしても、有効な値を取得できず、デフォルト値(1.0 = 最遠)が返されて画面が真っ白になってしまいます。深度情報を維持するためには、不透明オブジェクトの描画が終わった段階で、Zバッファの内容を別のテクスチャへ明示的に「コピー(格納)」して保存しておく必要があり、そのための設定がURP Assetとカメラの両方で必要になります。
3. 解決のための完全設定手順
深度情報を正しくシェーダーへ届けるためには、以下の2箇所での設定変更が必須となります。
ステップ①:URP Asset(Universal Render Pipeline Asset)の有効化
- プロジェクトウィンドウから、現在プロジェクトに割り当てられている UniversalRenderPipelineAsset を選択します(パスがわからない場合は `Project Settings > Graphics` の最上部をクリックしてアセットを特定できます)。
- インスペクターウィンドウを開き、General セクションを展開します。
- Depth Texture のチェックボックスを ON(有効) に変更します。
ステップ②:カメラ(Main Camera)のインジェクション設定
- シーン内の Main Camera(または描画を行っているサブカメラ)のゲームオブジェクトを選択します。
- Camera コンポーネント内の Rendering セクションを展開します。
- Depth Texture の項目を確認し、Use Pipeline Settings(パイプラインアセットの設定に従う)になっていることを確認します。もし個別で制御したい場合は On に設定します。
| 設定場所 | 設定項目 | 推奨値 | 効果 |
|---|---|---|---|
| URP Pipeline Asset | Depth Texture | ☑ ON | プロジェクト全体で深度テクスチャ生成パスを有効化する。 |
| Camera Component | Rendering -> Depth Texture | Use Pipeline Settings (または On) | このカメラのレンダリングパスにおいて深度情報のコピーを生成する。 |
4. トラブルシューティングとパフォーマンスへの配慮
深度テクスチャの生成は、GPUに追加のメモリコピーパス(Zバッファの内容をテクスチャへ書き写す処理)を強制するため、特にローエンドのモバイルデバイスやVRヘッドセット(Meta Quest等)では、ピクセルフィルレートの圧迫やVRAM帯域幅の消費に繋がり、フレームレートが僅かに低下する原因となります。実務における最適化の鉄則として、以下の対策を推奨します。
- 不要なカメラでは深度テクスチャをOffにする: シーン内に複数のカメラ(UI用カメラ、ミニマップ用カメラ、アイテムプレビュー用カメラなど)が存在する場合、それぞれのカメラのインスペクターで `Depth Texture` を明示的に Off に設定します。必要のないカメラまで深度コピーを走らせる無駄を徹底的に排除してください。
- ポストプロセスの適用順序との連携: 深度テクスチャが必要なのは、主に半透明エフェクトの描画時やポストプロセス(被写界深度やSSAIO等)の計算時です。これらを使用しないシーンやステージでは、動的にグラフィックス設定(URPアセット)の `depthTextureMode` をC#から切り替えて無効化する運用も効果的です。