3Dアクションゲームやシミュレーションゲームにおいて、炎、煙、爆発、魔法の障壁、あるいは飛び散る火花など、半透明な質感を持つVFXエフェクトは画面をリッチにするために不可欠な要素です。しかし、これら複数の半透明エフェクトを重ねて配置した際、「奥にあるはずの黒煙が、なぜか手前にある激しい炎の前に覆いかぶさって表示される」「カメラの角度をぐるぐると回すと、炎と煙の前後関係がパタパタと激しく入れ替わり、チカチカと点滅するようにチラつく」という、描画順序の不具合(ソーティングの破綻)に悩まされたことはないでしょうか。これは半透明のレンダリングにおける物理的な仕様制限によって発生します。本記事では、この前後関係崩壊バグの仕組みを、初心者にわかりやすい「劇場の半透明のシルクカーテン」の例え話を交えて解説し、これを明示的に制御する「Sorting Fudge(ソーティングファッジ)」の調整手順とベストプラクティスを提示します。
1. 例え話で理解する:『劇場の半透明カーテンと、監督の立ち位置』
この半透明エフェクトの描画順のチラつき問題を直感的に理解するために、『劇場のステージで、半透明の薄いシルクのカーテンを何枚も重ねて配置している舞台演出』を想像してみましょう。
舞台の演出家(開発者)は、手前に「赤いシルクのカーテン(炎のエフェクト)」を置き、その少し後ろに「黒いシルクのカーテン(煙のエフェクト)」を重ねて配置しました。通常の厚紙の壁(不透明オブジェクト)であれば、物理的に奥の壁は手前の壁に隠れて見えなくなるため、描画の順番を気にする必要はありません。
しかし、カーテンはどちらも「透けて見える半透明」です。劇場の監督(レンダリングエンジン)は、美しく重ね合わせて見せるために、「必ず奥の黒いカーテンを先にステージに吊るし、その上から手前の赤いカーテンを重ねて吊るす」という順番(奥から手前への描画)を守らなければなりません。
ところが、2枚のカーテンの吊り元位置(オブジェクトの中心座標)が極めて近い場合、監督はカメラの位置(プレイヤーの視点)を少し動かすたびに、「あれ?今はどっちが奥だっけ?」と測りかね、迷った末に吊るす順番を毎フレーム秒単位でコロコロと入れ替えてしまいます。その結果、赤い炎の前に黒い煙が突然割り込んで吊るされ、次の瞬間にはまた後ろに戻る、というようにステージ上のビジュアルが激しくチカチカと明滅し、観客を幻滅させてしまうのです。
これが、半透明オブジェクトにおける『重心距離ソートの限界』です。監督に対して「どんなに位置が近くても、必ず黒いカーテンを奥に、赤いカーテンを手前にして固定して吊るしなさい!」と明示的な優先ルール(Sorting Fudge)を与える必要があります。
2. 根本的な原因:深度書き込み(Depth Write)無効と簡易重心ソート
3Dグラフィックスにおいて、不透明オブジェクトは「デプスバッファ(深度バッファ)」という仕組みを使い、ピクセル単位で正確に前後関係を上書き判定して描画します。しかし、半透明オブジェクト(Render Queue = Transparent)は、自分より後ろにある背景を透けて見せる必要があるため、Zバッファへの書き込み(Depth Write)を基本的に行いません(無効化されます)。
深度バッファによる正確なピクセル判定が使えないため、Unityは代わりに「各ゲームオブジェクトのトランスフォームの重心位置(Center)からカメラまでの直線距離」を算出し、**「カメラから最も遠いオブジェクトから順に、手前に向かって上書きして描画していく(ペインターズアルゴリズム)」**ことで前後関係を擬似的に表現します。
エフェクトの重心同士が非常に近接している場合、カメラの視点角度が数度変わるだけで、計算上の「カメラからの距離」の順序が入れ替わってしまいます。これにより、描画される順番が毎フレーム反転し、重なり部分の前後関係が激しくチラつくフリッカーバグを引き起こします。
3. Sorting Fudgeを用いた具体的な解決方法
このソートの揺らぎを抑え、描画順を固定するために、Particle SystemのRendererモジュール内にある Sorting Fudge(ソーティングファッジ) を設定します。Sorting Fudgeは、距離計算の際にオブジェクトの重心距離に加算される「仮想的な奥行き値(バイアス)」です。**数値が小さい(マイナス側)ほどカメラに近い(手前)と判定され、大きいほどカメラから遠い(奥)**とみなされます。
設定例:炎と煙のソート固定
- 手前に表示させたい「炎」の Particle System を選択します。
- インスペクターの Renderer モジュールを展開します。
- Sorting Fudge の値を `0` (または小さめの値)に設定します。
- 奥に表示させたい「煙」の Particle System を選択します。
- 同様に Renderer 内の Sorting Fudge の値を `20` (炎より大きい値)に設定します。
// 手前に優先描画させたいエフェクト(炎、光線など)
[Renderer] -> Sorting Fudge: 0 (または -10)
// 奥側に沈めておきたいエフェクト(煙、モヤ、背景フォグなど)
[Renderer] -> Sorting Fudge: 20 (または 50)
これにより、カメラがどれだけ回転しても、計算上「煙」の距離は常に炎より20ユニット奥側にあると判定されるため、描画順が「煙(奥)➔ 炎(手前)」で完全に固定され、チラつきが100%解消されます。
4. 半透明ソート優先順位の早見テーブル
Unityが半透明アセットをソートする際、どのようなルールが優先されるかを整理したテーブルです。Sorting Fudgeを調整しても順序が変わらない場合は、より上位のレイヤー設定が競合していないか確認してください。
| 優先順位 | ソートキー項目 | 概要 |
|---|---|---|
| 1(最優先) | Sorting Layer | エディタのタグ設定で定義する描画レイヤー。異なるレイヤー間では、Fudgeや距離は一切無視されます。 |
| 2 | Order in Layer | 同一Sorting Layer内での整数値による優先順。数値が大きいほど手前に描画されます。 |
| 3 | Render Queue | マテリアルのシェーザパスに記述されるキュー(Transparentは3000)。数値が大きいほど手前。 |
| 4 | Sorting Fudge | 同一レイヤー・同一キュー内での個別エフェクトの深度バイアス。値が小さいほど手前。 |
| 5(最底辺) | Camera Distance | 上記がすべて同じ場合に適用される、物理的なカメラからオブジェクト中心までの実距離。 |