Three.jsポストプロセス設計:画づくりと負荷を両立するレンダリングパイプライン実務
Three.jsでポストプロセスに手を出すと、最初は「Bloomを足すとそれっぽい」「SSAOで立体感が増える」といった即効性に目が行きます。ただ、実装が育つほど効いてくるのは個別エフェクトの知識よりも、パイプライン全体を「パスの連鎖」として扱えるかどうかです。入力と出力が鎖状に依存し、深度・色空間・解像度の前提が一つずつ増えていく構造は、放置すると調整も性能も運用も崩れやすくなります。
実務で事故が多いのは、効果が弱いからではなく「どの段階の画像に対して調整しているか」が揃っていない状態です。トーンマッピングの前後で閾値の意味が変わり、線形とsRGBが混ざり、UI合成の位置が曖昧なままAAだけ強くする、といった小さなズレが連鎖して、数値調整が収束しなくなります。連鎖の前提と順序を仕様として固定できると、同じ数値が同じ意味を持ち、比較が成立して調整が一気に速くなります。
また、ポストは「盛るほど重くなる」よりも「重くなる理由が見えないまま盛られる」ことが問題になりがちです。フルスクリーン回数、解像度、サンプル数、深度依存の増加がどう積み上がるかを言語化できると、対策が「全部弱める」一択になりません。内部解像度の段階化、パス別解像度、プリセットで落とす順序、フォールバックといった逃げ道が設計として持てるようになります。
本記事は、EffectComposerを「便利な箱」として使うのではなく、中間バッファの流れ・パスの契約・順序・解像度・深度前提・UI合成・運用監視までを一本の設計として整理します。狙いは、エフェクトを増やすことではなく、増えても破綻しない基準線を作ることです。結果として、追加も撤去も比較も短くなり、画づくりの試行回数そのものが増える状態を目指します。
1. Three.jsポストプロセス設計対象を見誤らないための基礎
ポストプロセスを導入するとき、BloomやSSAOなど個別エフェクトの知識よりも先に、設計対象を「パス連鎖」として捉える視点が効いてきます。パスは単体で完結しているように見えて、入力と出力が鎖状に依存し、さらに深度や色空間といった目に見えない前提にも依存します。連鎖の性質を前提にすると、調整の収束、性能の予測、撤去の容易さが一段上がります。
「何が増えるのか」を言語化できると、実装が増えても破綻しにくくなります。フルスクリーン処理が増えるのか、サンプル回数が増えるのか、深度前提が増えるのか、UIとの干渉が増えるのかを把握できるだけで、対策は削除一択になりません。
1.1 パス連鎖が設計対象になる理由
ポストプロセスは、RenderTargetに描いた結果を次のパスが読み、別の中間に書き、最終的に画面へ出す、という連鎖で成立します。パスを一つ足す行為は、機能追加だけでなく「フルスクリーン描画が1回増える」「中間バッファの受け渡しが1段増える」「前提(色空間や深度)に依存する工程が増える」という意味も同時に持ちます。ここを把握していると、追加のたびに「品質と負荷の増え方」を予測でき、構成が育ったときの事故を減らせます。
調整が収束しない典型は、同じエフェクトでも「どの段階の画像」を基準に触っているかが揃っていない状態です。たとえばBloomの強さを上げ下げしても白飛びと効かなさを往復する場合、閾値の評価位置、トーンマッピングの位置、線形/sRGBの扱いが混ざっていることが多いです。連鎖として前提を固定し、順序を仕様として扱うと、同じ数値でも意味が一定になり、比較が可能になって収束が早くなります。
1.2 重くなる典型と悪化の連鎖
重さの原因は、多くの場合「フルスクリーン回数」「高解像度での重い処理(ブラーやSSAO)」「前提不足によるやり直し」に寄っていきます。これを「このパスが重い」で片付けると、削除しか打ち手が残りませんが、構造として捉えると、内部解像度の段階化やパス別解像度など、見た目を守りながら軽くする手段が見えてきます。重さはエフェクトの罪ではなく、回し方と解像度設計の結果として出ることが多いです。
悪化の仕方にも型があります。SSAOが汚いのでサンプル数を増やし、重くなったので内部解像度を下げ、下げた結果AAを強め、強めた結果UIが滲む、という具合に、局所改善が鎖として悪化します。逃げ道がないと「全部弱める」しかなくなり、結局ポストが価値を失います。内部解像度の段階、深度の可視化、UI合成方針、プリセットで落とす順序を先に持つと、調整が引き返せるため連鎖的な悪化を止めやすくなります。
1.3 標準レンダリングとの責務分離
rendererは「シーンを正しく描く」責務、composerは「画を作る」責務として境界を引くと、色空間やトーン周りの事故が減り、原因追跡も速くなります。境界が曖昧だと、トーンマッピングの二重適用やガンマの重複が起きやすく、端末差として「暗い」「沈む」「滲む」などの不具合が出やすくなります。さらに、どこを直すべきかが分からなくなり、修正が横断的になって運用が怖くなります。
実務では、最終の色調整・AA・演出の責務をどちらに置くかを固定し、二重適用を避けます。たとえば最終の画づくりをcomposerへ寄せるなら、renderer側は前提を揃える役に徹し、composer側で順序と設定を管理します。責務が分かれていると、シーンの変更がポストに波及しにくくなり、ポストの追加・撤去もcomposer内で完結しやすくなります。境界があるだけで、連鎖の制御は格段にしやすくなります。
パス連鎖を設計対象として扱うと、以降の判断(順序・解像度・深度前提・運用)が同じ物差しで語れるようになります。個別ノウハウの寄せ集めにならない状態を作れることが、長期的な画づくりの速度そのものになります。
2. Three.js EffectComposerの基本構造:中間バッファを理解して事故を減らす
EffectComposerは便利なユーティリティに見えますが、実務では「中間バッファの受け渡し(ping-pong)を管理する実行基盤」として理解するほど強くなります。中間バッファの流れが見えないと、結果が消える、最後の出力が分からない、サイズ変更で崩れる、といった事故の切り分けが難しくなります。内部モデルを短く固定すると、調整も最適化も手順になります。
中間バッファの流れを「追える」状態にするだけで、調整は勘から比較へ変わります。どのパスの出力を見ているのか、どの解像度で回っているのかが分かると、数値の意味が揃い、議論が速くなります。
2.1 Composerの実行モデルとping-pong
Composerは内部で複数のRenderTargetを交互に使い、各Passが「入力を読み、出力へ書く」という契約で連なるようにしています。パスを一つ追加すると、フルスクリーン描画が一回増えるだけでなく、バッファ切替とメモリアクセスも増えます。つまり、パス追加は「効果が増える」のと同時に「積み上がるコストが増える」行為であり、足し算の性質を持ちます。足し算の性質が見えると、どこで段階を切るべきかが判断しやすくなります。
この実行モデルを理解すると、壊れたときに「どの地点で壊れたか」を追えるようになります。たとえば真っ黒になった場合でも、RenderPassの出力が正しいのか、特定のShaderPassで壊れたのかを切り分けられます。反対に流れが見えないと、数値調整が効いているのか、別のパスが上書きしているのかが分からず、調整が迷走します。中間バッファの受け渡しは、ポストプロセスのデバッグ手順そのものです。
2.2 PassとRenderTargetの契約
Passは処理単位ですが、実務では「前提」と「副作用」を明記して扱う必要があります。深度が必要か、HDR前提か、入力が線形か、解像度が固定か、といった前提が揃わないと、Pass自体は正しく動いていても結果が破綻します。SSAOのように深度とスケールに敏感なパスは、前提が崩れた瞬間にノイズへ転び、ノイズ対策としてサンプル数を増やして性能が崩れる、という形で負債化しやすいです。前提の明文化は、導入コストを下げるよりも運用コストを下げます。
RenderTargetは「中間結果を入れる箱」ではなく、品質と負荷を決める設計要素です。解像度・フォーマット・深度の有無がコストとメモリを左右し、ブラー系は低解像度でも成立しやすい一方、AAや深度系は解像度に敏感です。RTをどこで落とすかを選べるようになると、同じ雰囲気を守りながら劇的に軽くできます。逆にRT設計が曖昧だと、全パスが高解像度で走り続け、最終的にパス削除しか手が残りません。
2.3 最終出力と合成の責務
Composerは最終出力を担い、画面へ出すのか、別RTへ出すのかが構成の分岐点になります。UIを別レイヤーで合成する場合、3Dの最終出力は「UIの手前」で止める設計になりやすく、同一キャンバスでUIも描く場合はAAの位置やブレンドの前提が変わります。UIが滲む、透明がにじむ、色が沈むといった体験上の不具合は、合成の責務が曖昧なときに出やすく、原因が複合しやすいです。合成の位置が固定されるだけで、UI関連の事故は減ります。
色空間とトーンの責務も、最終出力の設計に直結します。rendererでトーンをかけてからcomposerでさらに補正をすると、二重適用で見た目が崩れやすくなります。逆にcomposer側へ寄せるなら、renderer側は前提を揃える役に徹する方が安定します。どこで「最終の見た目」が確定するかを固定すると、後からパスを足しても破綻しにくくなり、調整の比較も容易になります。
中間バッファを「仕様の中心」として扱えるようになると、Composerは単なる便利ツールではなく、運用の土台になります。見えない流れを追える状態があるだけで、追加・撤去・最適化の会話が短くなり、手戻りが減っていきます。
3. Three.jsポストプロセスのパス設計 原則と順序で破綻を防ぐ
パス設計は「好きなエフェクトを並べる」作業ではなく、「順序と前提を揃えた工程を組む」作業です。順序が悪いと、数値調整で直らない破綻が起き、調整は収束しません。順序が良いと、エフェクトが少なくても雰囲気が出やすく、撤去やプリセット化も簡単になります。補正・演出・AA・深度依存という軸で整理すると、構成が育っても迷いにくくなります。
順序は「正解が一つ」ではありませんが、「理由が揃っている」ほど強くなります。理由が揃うと、誰が触っても大きく崩れにくく、調整が比較で進みます。
3.1 補正系と演出系を分ける
補正系(露出、トーンマッピング、ガンマ、カラーグレーディング)は「全体の基礎」を作る処理です。ここが揺れると、後続のBloomやVignetteが同じ設定でも別物に見え、調整が収束しません。実務では、補正系を一箇所に集約し、順序と前提(線形/sRGB)を固定します。固定すると、演出は「基礎の上に足す」形になり、比較が容易になります。基礎が固定されているほど、演出の変化は意図として説明しやすくなります。
演出系(Bloom、DOF、Filmなど)は世界観を作りますが、積むほど相互作用が増え、破綻しやすい領域です。撤去しやすい構造がないと、運用が怖くなり、最終的に演出は固定値として触れなくなります。プリセットとフラグで切れる形を同時に作り、最大構成が常に走らない状態を保つと、演出の価値を維持しやすくなります。演出を守るには「盛る」より「落とせる」ことが効いてきます。
3.2 AAを先に置くか後に置くか
AAは「最後に置く」が直感的ですが、UIや文字が同一キャンバスにある場合、FXAAで滲むことがあります。TAAは高品質ですが、履歴管理とゴーストが難しく、動きが多いシーンでは逆効果になり得ます。つまりAAは、画づくりの最後の飾りではなく、プロダクト体験(可読性、疲労、動きの気持ちよさ)と密接です。UIが主役の場面と3Dが主役の場面で、最適なAAは変わります。
実務では、AAを固定位置にせず、少なくとも2パターン比較できるようにします。たとえば「演出後にFXAA」「補正後にTAA」のように、目的に応じて配置を変える発想です。UIを別レイヤーで合成できるならAAの影響を避けやすく、選択肢が広がります。AAを仕様として扱い、プリセットに落とすと、演出を足しても可読性が崩れにくくなり、品質とUXが同時に守りやすくなります。
3.3 深度依存パスの前提条件
SSAOやDOFは深度が正しく取れていることが前提ですが、この「正しさ」は深度の存在だけでは足りません。near/farの設定、スケールの整合、解像度の一致、透明物の扱いが揃って初めて、深度は意味を持ちます。前提が崩れると、効果はノイズになり、ノイズ対策でサンプル数が増え、性能が崩れるという悪循環に入ります。深度依存は、成功すると効果が大きい一方、前提が揃わないとコストだけ増えやすい領域です。
深度依存パスを入れるなら、深度可視化を用意し、半径や強度をスケールに合わせ、最後にノイズ対策(サンプル数やTemporal)を詰める順が安全です。深度の精度やスケールが揃うだけで、SSAOは「汚れ」から「狙った陰影」に変わります。前提を整える投資は地味ですが、調整時間と回帰を大きく減らし、結果として深度系がプロダクトに残りやすくなります。
3.4 パス順序が破綻する代表例
破綻しやすいのは、カラー空間とトーンの順序が混ざるケースです。トーン前提で閾値を切るBloomをトーン後に適用すると、閾値の意味が変わり白飛びしやすくなります。逆にBloom前に強い色補正を入れると発光が過剰に増幅され、画が眠くなります。数値を触っても直りにくいのは、問題が数値ではなく順序だからです。順序が揺れると、調整の基準が消え、議論が感覚論になります。
もう一つの破綻は、透明物と深度系の衝突です。透明は深度に書き込まれないことが多く、SSAOやDOFが奥行きを誤解します。無理に直そうとすると例外が増え、パイプラインが複雑化して運用が止まります。透明を別扱いにする、深度系の対象を限定する、プリセットで切る、といった割り切りを仕様として持つと、破綻は局所化し、回帰も減ります。順序設計は、割り切りを含めて初めて安定します。
順序を理由ごと固定できると、ポストプロセスは追加しても崩れにくくなります。補正・演出・AA・深度前提の境界を揃えるだけで、数値調整の難易度は大きく下がり、チーム内の合意も取りやすくなります。
4. Three.jsポストプロセスの解像度設計 DPRと内部スケールで品質と負荷を両立する
ポストプロセスの性能設計で最も効くレバーは解像度です。フルスクリーン処理はピクセル数に比例するため、DPRをそのまま採用すると負荷が跳ね、最終的にパス削除しか手がなくなります。解像度戦略を先に設計しておくと、見た目を守りながら負荷を落とす逃げ道が増えます。解像度は画づくりと性能の両方に影響するため、初期から方針を固定すると運用が安定します。
解像度は「高いほど良い」ではなく、「どこに解像度を使うか」が重要になります。シャープさを守るのか、にじみを作るのか、ノイズを抑えるのかによって最適解は変わり、段階設計があるほど現実的に扱えます。
4.1 DPRと内部解像度を分けて考える
DPRは上げるとシャープになりますが、ピクセル数は概ねDPR²で増えます。DPR=2なら約4倍、DPR=3なら約9倍に近い負荷増が起き得ます。ポストが入るとこの影響は露骨で、BloomやAAなどのフルスクリーンパスが多いほど支配的になります。実務では、DPRに上限を設けるのが一般的です。上限がないと、高DPR端末が「最も重い端末」になり、品質の期待と体験が噛み合わなくなります。
内部解像度(internalScale)は「見た目の芯」を守りつつ落とせるレバーです。0.7〜0.9程度に落とすだけで大きく軽くなることが多く、フルスクリーンパスが多い構成ほど効きます。DPRでシャープさを確保しつつ、内部解像度で安定化する分担にすると端末差を吸収しやすくなります。解像度は一つの数値ではなく役割分担で設計すると、調整も運用も迷いにくくなります。
4.2 内部スケーリング戦略(段階と動的制御)
内部解像度を連続的に動かすと、見た目が揺れてユーザーにバレやすく、AAやノイズのパラメータもズレやすくなります。実務では、段階(0.7/0.85/1.0など)で運用する方が安定します。段階にすればテスト対象が減り、回帰防止にも効きます。段階の数を増やしすぎると運用が重くなるため、まずは3段階程度が扱いやすいです。段階があると、品質の合意も作りやすくなります。
動的解像度を入れる場合は、フレーム時間を見て段階的に落とす設計が扱いやすいです。ただし頻繁に上下すると逆効果なので、ヒステリシスとクールダウンが必要です。動的解像度は「常時最適化」ではなく「事故を防ぐ保険」として設計すると体験が安定します。プリセットを基本にしつつ、厳しい環境だけ段階的に落とすと、画づくりの価値を保ったまま配布の現実に合わせられます。
4.3 パスごとの解像度を分ける設計
Bloomやブラー系は低解像度でも成立しやすく、パス別解像度の効果が大きい代表です。低解像度RTで走らせて合成すると、同じ雰囲気を保ったままコストを大きく下げられます。一方、SSAOやAAは解像度に敏感で、落としすぎるとノイズやジャギーが目立ちます。パス別解像度は「落として良い対象」と「落とすと壊れる対象」を選び分ける設計です。選び分けができるほど、削除に頼らずに最適化できます。
ただし、パス別解像度は管理が難しくなります。リサイズ更新漏れ、サンプル半径の意味の変化、合成時のスケール差が事故になります。導入するなら、解像度に応じて半径や強度を補正する仕組みを持つと、見た目が崩れにくくなります。パス別解像度は「軽いのにそれっぽい」を作りやすい反面、運用設計込みで扱うと安定します。
4.4 リサイズ処理の実務テンプレ
リサイズでの破綻は「rendererだけ更新」「composerだけ更新」から起きます。renderer/composer/パス別RTを一箇所で一貫更新し、更新漏れを構造で防ぐと、サイズ変更時の不具合は減ります。DPR上限と内部解像度を同時に扱い、カメラ更新も同じ場所で行うと、変更点が散らばらず追いやすくなります。リサイズは頻繁に発生するため、テンプレ化の効果が大きい領域です。
type ResizeDeps = {
renderer: THREE.WebGLRenderer
composer: EffectComposer
camera: THREE.PerspectiveCamera | THREE.OrthographicCamera
setPassSize?: (rw: number, rh: number) => void
}
export function resizePipeline(
deps: ResizeDeps,
cssW: number,
cssH: number,
dpr: number,
internalScale = 1.0,
dprCap = 2
) {
const pixelRatio = Math.min(Math.max(1, dpr || 1), dprCap)
deps.renderer.setPixelRatio(pixelRatio)
deps.renderer.setSize(cssW, cssH, false)
const rw = Math.max(1, Math.floor(cssW * pixelRatio * internalScale))
const rh = Math.max(1, Math.floor(cssH * pixelRatio * internalScale))
deps.composer.setSize(rw, rh)
if ('aspect' in deps.camera) deps.camera.aspect = cssW / cssH
deps.camera.updateProjectionMatrix()
deps.setPassSize?.(rw, rh)
}
解像度設計が先に固まると、パス追加のたびに性能が不安定になる状態を避けやすくなります。DPR・内部解像度・パス別解像度・リサイズ更新を一体として扱えるほど、画づくりと負荷の両立は現実的になります。
5. Three.jsポストプロセスの代表パス 使い分けで理解して破綻を避ける
代表パスは多いですが、実務で重要なのは「何が得意で、どこで壊れやすいか」をセットで理解することです。強いパスほど前提が増え、前提が崩れると汚くなり、撤去されがちです。Bloom、SSAO、AA、トーンという頻出要素を中心に、使い分けの判断軸を整理します。
使い分けは、効果の派手さではなく「前提が揃うか」「落とせるか」「UIと衝突しないか」で決まる場面が多いです。そこを押さえると、導入は計画的になり、調整も短くなります。
5.1 Bloom(UnrealBloomPass)の設計ポイント
Bloomは雰囲気作りに効きやすい一方、白飛びとにじみで破綻しやすいです。strengthを上げる前に、露出とトーン設計を整え、閾値(threshold)で「光らせる範囲」を制御するのがコツです。閾値が低いと全体が光って画が眠くなり、コントラスト補正で取り返そうとしてさらに破綻する、という調整ループに入りがちです。Bloomを気持ちよく使うには、閾値とトーンの役割分担を固定し、同じ入力条件で比較できる状態を作る必要があります。
Bloomは低解像度でも成立しやすいので、パス別解像度の恩恵が大きいパスです。低解像度に落とすと質感は変わりますが、その変化は「にじみ」として受け入れられやすいことが多く、運用上の妥協点になりやすいです。数値だけで戦うより、解像度と順序で戦った方が収束が早い場面が多く、プリセットで段階を作ると本番での安定性も上がります。Bloomは強さより、土台の固定が先に効きます。
5.2 SSAO/SSGIの適用条件と限界
SSAOは立体感を出しますが、深度品質に支配され、ノイズが出やすいです。透明物や薄いジオメトリ、スケール差が大きいシーンでは破綻しやすく、万能にしようとするとサンプル数が増えて性能が崩れます。実務では「適用対象を限定する」判断が現実解になりやすく、屋内中心や硬い物中心、特定レイヤーのみなどの割り切りが効きます。限定するほど、ノイズ対策のコストが抑えられ、見た目も安定しやすくなります。
SSGIはさらに前提とコストが重くなるため、導入するならプリセットとフォールバックが必須です。HighではSSGI、MedではSSAO、Lowでは無し、といった階段を作ると、端末差を吸収しながら導入できます。深度系は「入れたら豪華」ではなく「前提が揃って初めて価値が出る」領域なので、前提が揃わない環境向けの逃げ道があるほどプロダクトに残りやすくなります。結果として、深度系の価値を守るのは設定の段階設計です。
5.3 FXAA/TAA/SMAAの選定基準
FXAAは導入が簡単で軽い一方、文字やUIが滲みやすいです。UIが重要なプロダクトでは、FXAAを最後に置いたことで可読性が落ち、結果としてオフにされることがあります。TAAは高品質ですが、履歴管理とゴーストが難しく、動きが多いシーンでは破綻しやすいです。SMAAはバランス型ですが、導入と運用の手間が増えます。AAは画の品質だけでなく、UIの読みやすさや操作感も含めて評価する必要があります。
実務では、まずFXAAで最低ラインを作り、必要ならTAAを選択肢として用意する段階が扱いやすいです。UIを別レイヤーで合成できるならAAの影響を避けやすく、選択肢が広がります。AAの位置と方式は、演出の強さとセットで効いてくるため、プリセットに落として「場面に応じて変えられる」形にすると運用が安定します。AAを固定値として扱わず、制御可能な仕様として扱うほど強くなります。
5.4 トーンマッピングとカラー空間
カラー空間とトーンは運用事故が最も多い領域です。sRGBとLinearの混同、トーンマッピングの二重適用、ガンマ補正の重複が「端末で違う」「急に暗い」といった形で現れます。実務では、renderer側で何をやり、composer側で何をやるかを固定し、順序を仕様として扱います。順序が固定されると、Bloomの閾値や露出の調整が収束しやすくなり、他パスの調整も揺れにくくなります。
トーンマッピングは「どの段階の画像」を基準に設計するかが重要です。トーン前提の閾値をトーン後の値で切ると破綻します。これを避けるには、トーンの責務を一箇所へ寄せ、他のパスはその前提で動くように設計します。カラー空間が固定されるほど、演出の追加・撤去が怖くなくなり、見た目の比較がしやすくなります。結果として、画づくりの議論が短くなります。
代表パスは、強いほど前提が増えます。得意と落とし穴をセットで理解し、プリセットと解像度戦略に落とし込めると、導入は計画的になり、撤去も怖くなくなります。
6. Three.js深度・法線・マスク設計 ポストの土台を固める
深度・法線・マスクは、ポストプロセスの前提データです。前提が崩れると深度系が破綻し、デバッグが難しくなります。ここを固めるほど、SSAOやDOFの調整は短くなり、回帰も減ります。逆に後回しにすると、見た目を合わせるための例外が増え、運用が止まりやすくなります。
前提データは「取れているか」ではなく「期待通りに使えるか」で評価すると、準備の質が上がります。深度の精度、透明の扱い、マスクの運用方式が揃うと、深度系の成功率が大きく上がります。
6.1 DepthTextureの用意と罠
DepthTextureは「付ければOK」ではありません。near/farの設定、解像度の一致、更新タイミングが揃って初めて意味を持ちます。near/farが極端だと深度精度が落ち、SSAOがノイズだらけになります。解像度がズレるとサンプル位置がズレてハローが出ます。深度は見えないため更新漏れに気づきにくく、後から深度系を入れた瞬間に壊れる典型原因になります。深度系の不具合が「たまに」起きるときは、更新漏れが疑いどころになります。
深度の可視化を常に持ち、リサイズで深度が更新されていることを確認できる状態を作ると、切り分けが速くなります。深度は「取れているか」ではなく「期待通りに使えるか」が重要で、期待通りに使える深度があるだけでSSAOやDOFの調整は別物のように楽になります。地味な準備ですが、投資対効果が高く、後で取り返すのが難しい領域でもあります。
6.2 マスク(レイヤー/Stencil/選択描画)の考え方
マスクは「特定オブジェクトだけBloom」など頻出ですが、方法が複数あり運用コストが違います。レイヤー分離は扱いやすい一方、描画回数が増えやすいです。Stencilは強力ですが設定漏れが事故になりやすく、チームでの運用が難しいことがあります。選択描画は柔軟ですが場当たりになりやすく、後から整理しづらいです。どれも一長一短なので、要件と運用体制で選ぶのが現実的です。
最初はレイヤー分離で成立させ、必要になった段階でStencilや専用マスクパスへ寄せる流れが回りやすいです。マスクは「できる」より「回せる」が重要で、回せないマスクは結局オフになります。運用の現実を優先して設計すると、長期的に表現の幅を維持できます。表現の幅は、技術だけでなく運用方式で守るものです。
6.3 透明物とポストプロセスの衝突
透明物は深度に書き込まれないことが多く、深度依存パスと衝突しやすい代表です。透明を含むシーンでSSAOやDOFを万能にしようとすると、例外処理が増え、品質も性能も落ちます。透明は別パスにする、AO対象から除外する、DOF対象から外す、といった割り切りが必要になります。割り切りがないと、パイプラインが例外だらけになり、最終的に誰も触れなくなります。
透明物はUIとも絡みます。半透明のUIパネルがAOで汚れると可読性が落ち、プロダクト体験が下がります。透明の扱いを仕様として固定すると、深度系の品質も安定し、回帰も減ります。透明は難所ですが、方針が決まると運用が楽になる領域であり、先に決めるほど後の調整が短くなります。
6.4 DOFの成立条件
DOFは雰囲気に効きますが、成立条件が多く破綻もしやすいです。深度が正しいこと、焦点距離の設計があること、被写体スケールが揃っていること、透明物の扱いが決まっていることが前提になります。前提が崩れると境界がギザギザになり、ボケが不自然に広がります。調整で誤魔化すほど設定が肥大し、運用が止まります。導入コストの低さではなく、運用コストの低さで評価すると、判断が安定します。
DOFは最後に入れる候補として扱い、プリセットでオンオフできる構造にすると運用が回りやすくなります。プロダクト用途ではDOFがUXを下げることもあるため、常時オン前提で設計しない方が安全です。前提が揃った環境だけで効かせる、という段階設計にすると、表現力を残しつつ現実的に配布できます。深度系は段階があるほどプロダクトに残りやすいです。
土台が固まると、深度系の導入は「難しい」から「手順がある」に変わります。前提が揃った状態で使う深度系は強く、前提が揃わない深度系はコストだけ増えます。
7. Three.jsポストプロセスの性能設計 どこで重くなるかを構造で掴む
性能問題は「重いパスを削る」だけでは解決しません。重くなる理由を分類し、解像度・回数・サンプル数・パス数というレバーで制御できる形に落とす必要があります。ポストはフルスクリーン処理が中心なので、解像度設計とパス設計が最適化の大部分を占めます。構造で掴めると、改善は勘から実験になります。
性能の議論が長引くときは、観測と分類が足りないことが多いです。フル解像度のパス数、ブラーのサンプル、深度系のノイズ対策など、疑う順序が揃うだけで、改善の初手が揃います。
7.1 パス数とフルスクリーン描画のコスト
パスが増えるほどフルスクリーン描画が積み上がり、GPU時間が増えます。最初にやるべきは「何パスあるか」「どれがフル解像度か」を見える化することです。見える化ができれば、内部解像度の調整やブラー系の低解像度分離など、効く対策を早く選べます。見える化せずに細かいシェーダ調整をしても、効果が小さくなりがちです。積み上げの量を把握することが、最初の最適化になります。
パス数は「増え方」が問題です。とりあえず足すが続くと、いつの間にかパスが増え、調整とテストが破綻します。実務では、パスを増やすたびに「守る価値」と「落とす手段(プリセット)」をセットで設計し、最大構成が常に走る状態を避けます。最大を磨くより、段階で守る方が安定し、結果として表現を守りやすくなります。
7.2 ブラー回数・カーネルサイズの設計
ブラーは半径を上げるほどサンプル数が増え、コストが急に跳ねます。実務では、半径を上げるより、解像度を落として回数を調整する方が破綻しにくいです。Bloomのにじみは低解像度での数回ブラーでも十分なことが多く、見た目の差は「質感」として許容されやすいです。ブラーは数値調整ではなく処理設計で勝つ領域であり、解像度と回数の組み合わせで戦うほどコストに効きます。
解像度を落とすと半径の意味が変わる点には注意が必要です。低解像度で同じ半径を使うと相対的に強く見えるため、解像度に応じた補正が必要になります。補正があると、軽くしても画が崩れにくくなり、調整も収束します。ブラーの設計が整うと、ポスト全体のコスト構造が読みやすくなります。
7.3 低解像度バッファの活用
低解像度バッファは最適化の主役ですが、乱立させると管理が破綻します。リサイズ更新、フォーマット、合成順序が増え、デバッグが難しくなります。実務では「低解像度RTは用途別に数を絞る」方が成功しやすいです。Bloom用にだけダウンサンプルチェーンを持ち、その他はcomposer全体の内部解像度で吸収する、といった割り切りが回ります。割り切りがあるほど、運用コストは下がります。
低解像度バッファを導入するなら、リサイズ更新を一元化し、どのパスがどの解像度で動いているかをログに出せるようにすると運用が楽になります。低解像度は効果が大きいほど運用のための設計が必要で、設計があると「軽いのにそれっぽい」構成が作りやすくなります。設計がないと「軽いが崩れる」になり、結局戻されます。
7.4 GPUボトルネックの見分け方
ポストが重いとき、原因がGPUなのかCPUなのかを混同すると対策が外れます。フルスクリーンパスが支配的ならGPU寄り、ドローコールやマテリアル切替が支配的ならCPU寄りになりやすいです。まずはパスのオンオフで差分を見る、内部解像度を落としてどれだけ改善するかを見る、といった実験で分類すると、厳密なGPUタイム計測がなくても判断できます。差分の出方は、原因の位置を教えてくれます。
原因と症状の対応を整理しておくと、初手が揃います。高解像度フルスクリーンでGPU時間が増えるなら内部解像度、ブラーが露骨に重いなら低解像度RT、深度系が汚いなら前提とサンプル設計、という方向が見えます。性能は「最適化の技術」より「切り分けの技術」で決まる場面が多いです。切り分けができるほど、最適化は短く終わり、画づくりへ時間を戻せます。
性能設計を構造で掴めると、最適化は「削る」から「制御する」へ変わります。段階と解像度のレバーがあるだけで、表現の幅を保ったまま安定させやすくなります。
8. Three.jsポストプロセスのコード構造 拡張しやすさが命
実務で最も多い崩壊は、composerへのaddPassが増殖して撤去できなくなることです。拡張しやすさは性能以上に重要で、拡張できない構造は最終的に品質も性能も保てません。設定とビルドを分け、依存を宣言し、デバッグ可視化を仕込むと、ポストは長期運用に耐える形になります。コードの見た目より、運用の強さを優先すると結果が安定します。
構造が整うほど「試せる回数」が増えます。試せる回数が増えるほど、良い画に到達する確率も上がるため、コード構造は表現力の土台でもあります。
8.1 パス生成を「設定」から分離する
パス追加を直書きで積むと、プリセットや端末別設定が難しくなります。設定(どのパスを有効にするか、品質値は何か)と、ビルド(composerへどう組むか)を分けると、撤去や再構成が簡単になり、順序変更の影響も管理しやすくなります。設定がそのまま「プロダクトの画づくり仕様」になるため、合意形成も進めやすくなります。見た目を合わせる会話が、コードの差分ではなく設定の差分でできます。
この分離は調整速度にも効きます。露出やBloom閾値をコードから切り離せると、リリース前の調整が現実的になり、調整が収束しやすくなります。ポストは調整が多い領域なので、コード構造が調整速度を決めます。設定を薄く保ちつつ、ビルドを確実にする構造が、最終的に一番強い運用になります。
8.2 有効/無効切替を機能フラグ化する
端末差が大きい以上、機能フラグは必須に近いです。低性能端末ではSSAOを切る、Bloomは低解像度に落とす、といった段階的有効化ができます。フラグがif文で散らばると破綻するので、フラグは設定層に集約し、ログで「有効パス一覧」を出せる形にします。ログに出せると障害対応が速くなり、運用コストが下がります。ユーザーからの報告を再現に繋げられるだけで、改善の速度は大きく変わります。
フラグは「止める」運用にも使えます。リリース後に特定環境で不具合が出た場合、そのパスだけ止められると被害が小さくなります。ポストは贅沢品になりやすいので、止められる設計は本番で価値を持ちます。止める条件(エラー率、フレーム時間)もセットで設計すると、挑戦的な表現を入れても運用で回収しやすくなります。
8.3 依存関係(深度必要、前提パス)を宣言する
SSAOは深度が必要、TAAは履歴が必要、Bloomはトーン設計の前提がある、など依存を宣言しないと、単体オンで真っ黒になる事故が起きます。依存を宣言できると、ビルド時に不足を検知し、代替へ落とす、UIで警告する、といった運用が可能になります。壊れ方を設計できると、壊れたときに直せる状態が作れます。直せる状態があるだけで、導入の心理的負担は大きく下がります。
依存宣言は最初から完璧でなくて構いません。最低限「深度が必要」「RenderPassが必要」程度でも、多くの事故を減らせます。宣言できる範囲から始め、事故が起きたら追加する方針が現実的です。依存は「仕様」として増えていくものなので、増える前提で置き場を用意しておくと、後から整えやすくなります。
8.4 デバッグ可視化を仕込む
中間RTを画面に出せるデバッグは、詰まりを一気に減らします。深度表示、SSAOだけ表示、Bloomだけ表示、合成前表示などを切り替えられると、どの時点で壊れたかが分かります。外部ツールが使えない環境でも切り分けできるため、デバッグは後付けではなく最初から組み込みます。原因追跡が「推測」から「確認」へ変わると、調整は短く終わります。
デバッグ可視化はサポートにも効きます。特定端末で崩れる場合、可視化モードのスクリーンショットだけで原因が絞れることがあります。ユーザーの環境を完全に再現できないWebの性質上、可視化は強い武器です。可視化が常にある状態を作ると、ポストは「怖くて触れない」領域になりにくくなります。
type PostConfig = {
preset: 'low' | 'med' | 'high'
aa: 'fxaa' | 'smaa' | 'taa' | 'off'
bloom: { enabled: boolean; strength: number; threshold: number; radius: number }
ssao: { enabled: boolean; intensity: number }
tone: { exposure: number }
debugView: 'final' | 'depth' | 'ssao' | 'bloom'
}
export function buildPostPipeline(
renderer: THREE.WebGLRenderer,
scene: THREE.Scene,
camera: THREE.Camera,
cfg: PostConfig
) {
const composer = new EffectComposer(renderer)
const enabledPasses: string[] = []
composer.addPass(new RenderPass(scene, camera))
enabledPasses.push('render')
if (cfg.ssao.enabled) {
const pass = new SSAOPass(scene, camera, 1, 1)
pass.kernelRadius = cfg.ssao.intensity
composer.addPass(pass)
enabledPasses.push('ssao')
}
if (cfg.bloom.enabled) {
composer.addPass(new UnrealBloomPass(new THREE.Vector2(1, 1), cfg.bloom.strength, cfg.bloom.radius, cfg.bloom.threshold))
enabledPasses.push('bloom')
}
if (cfg.aa === 'fxaa') {
composer.addPass(new ShaderPass(FXAAShader))
enabledPasses.push('fxaa')
}
if (cfg.debugView !== 'final') {
composer.addPass(new ShaderPass(makeDebugShader(cfg.debugView)))
enabledPasses.push(`debug:${cfg.debugView}`)
}
return { composer, enabledPasses }
}
function makeDebugShader(mode: 'depth' | 'ssao' | 'bloom') {
return {
uniforms: { tDiffuse: { value: null } },
vertexShader: 'varying vec2 vUv; void main(){ vUv=uv; gl_Position=projectionMatrix*modelViewMatrix*vec4(position,1.0); }',
fragmentShader: 'uniform sampler2D tDiffuse; varying vec2 vUv; void main(){ gl_FragColor=texture2D(tDiffuse,vUv); }',
}
}
コード構造が整うほど、試行錯誤が怖くなくなります。試せる回数が増えるほど、画づくりは前に進み、性能と運用の両立も現実的になります。
9. Three.jsポストプロセスとUI/UX 表現をプロダクトに接続する
ポストプロセスは世界観を作りますが、プロダクトでは「読める」「迷わない」「疲れない」も同時に守る必要があります。演出が強いほどUIとの衝突が起きやすく、アクセシビリティ面の配慮も必要になります。体験の仕様として設計に含めると、運用が安定します。
UI/UXの観点を入れると、ポストは「見栄え」から「体験の制御」へ変わります。制御できるほど、表現の強さを保ちながらプロダクト要件に合わせやすくなります。
9.1 演出をプリセットへ落とす
演出を固定値にすると、端末差とコンテンツ差で破綻します。プリセット(Low/Med/High)とユーザー設定に落とすと事故が減ります。Bloom強度、SSAOオンオフ、AA種別、内部解像度をプリセットでまとめると、組み合わせ爆発を避けつつ運用できます。設定は増やしすぎるほど壊れやすくなるため、自由度より再現性を優先するのが実務的です。再現性があるほど、問題の切り分けも速くなります。
プリセット設計では「落とす順序」も含めると運用が迷いません。高負荷時に内部解像度を落とし、それでも厳しければSSAOを切り、最後にBloomを弱める、といった段階を決めると、体験を守りながら止血できます。段階があると、演出の価値を守ったまま配布の現実に合わせられます。最大構成を固定するより、段階で守る方が長く続きます。
9.2 UIテキストとポストの干渉を避ける
AAやBloomはUIテキストを滲ませることがあります。特にFXAAは文字がぼけやすく、ユーザーが最も不満を感じやすい領域です。UIが重要なら、UIを別レイヤー(DOMや別Canvas)で合成する判断がよくあります。あるいは、モーダル表示中はポストを弱めるなど、状態に応じて演出を変える設計も有効です。UIが主役の瞬間に演出を抑えるだけで、体験の評価が大きく変わることがあります。
ポストは「常に最大」である必要がありません。画面遷移や入力中、テキストが主役の場面では演出を抑え、3Dが主役の場面で演出を効かせる、といった文脈制御ができると、世界観と可読性が両立しやすくなります。演出の強さを仕様として制御できると、後からエフェクトを足してもUXが崩れにくくなり、調整の議論も短くなります。
9.3 アクセシビリティ配慮
強いフラッシュ、過剰なノイズ、ちらつきは、光過敏や疲労の原因になり得ます。プロダクト用途では「演出を抑えたモード」があるだけで、体験の安全性が上がります。表現が価値であるほど、ユーザーが選べる形にしておくと長期的に支持されやすくなります。特定のユーザーに強く刺さる表現ほど、別のユーザーには負担になることがあります。
アクセシビリティはサポートコストにも効きます。目が疲れる、酔う、といった声は性能問題と同じくらい離脱に直結します。プリセットとトグルで逃げ道を作る設計は、結果としてプロダクトの継続運用を楽にします。表現を守るためにこそ、抑える手段を設計に含める価値があります。
UI/UXの観点が入ると、ポストプロセスは「綺麗」だけで評価されなくなり、体験として制御されるようになります。制御できるほど、表現の強さを保ったままプロダクトへ接続できます。
10. Three.jsポストプロセスのテストと回帰防止 壊れやすさを前提に整える
ポストは環境差が出やすく、回帰が起きやすい領域です。設定が増えるほど組み合わせも増え、見た目の変化が「バグなのか意図なのか」曖昧になります。現実的に回せるテスト方針と、影響範囲を限定する設計があると、ポストは「怖くて触れない」状態になりにくくなります。テストを増やす前に、壊れる範囲を小さくする設計が効きます。
回帰が増えると、演出は固定値になり、改善が止まります。触れる状態を維持するには、許容と禁止の線引き、代表シーン、プリセットの固定が必要になります。
10.1 画像差分テストの現実解
ポストはピクセル完全一致が難しいため、許容誤差つき差分が現実的です。差分が一定以上の領域だけ検知する、PSNRや閾値で判定する、といった方法を取ると回ります。重要なのは、偽陽性が少なく「変化があったときに原因が追える」ことです。偽陽性が多いテストは誰も見なくなるため、厳密さより継続性が価値になります。継続できるテストが、回帰を減らします。
テストシーンは増やしすぎず、代表シーンを固定します。屋内、屋外、透明物多め、発光多めなど、パスが壊れやすい条件を含む数枚に絞り、プリセットごとに撮ると回ります。網羅より継続が重要で、継続できる設計が回帰を減らします。代表シーンが固定されると、調整も比較可能になり、合意形成も速くなります。
10.2 GPU差・ブラウザ差の許容範囲を決める
GPU差はゼロにできません。浮動小数の差、フィルタの差、精度の差が出ます。実務では「どの差は許容し、どの差はバグとするか」を決めます。たとえばBloomのにじみが微妙に違うのは許容するが、SSAOが真っ黒になるのは許容しない、という線引きです。線引きがないと検証が終わらず、導入が止まります。許容が明文化されると、レビューも短くなります。
許容範囲はプリセットとセットで扱うと運用が楽です。Highは多少差が出てもよいが、Lowは安定させる、というように要求を分けると、端末差に対して現実的な判断ができます。許容は妥協ではなく、配布と品質の両立のための仕様です。許容があることで、表現を諦めずに運用へ持ち込めるケースも増えます。
10.3 設定変更の影響範囲を限定する
回帰を減らす最大の手は「壊れる範囲を小さくする」ことです。パスごとに設定を閉じる、依存関係を宣言する、プリセットの組み合わせを固定する、といった設計が効きます。設定が他パスへ波及しないほど差分の原因が追いやすくなり、回帰が局所化します。テストを増やす前に、設計で影響範囲を限定するのが実務的です。設定が散らばるほど、回帰の原因も散らばります。
トーンや色空間は全体へ波及するため、変更はレビュー必須にするなどガードレールを用意すると運用が安定します。回帰防止はテストだけでなく、変更の扱い方の設計でもあります。変更の扱いが揃うほど、チーム全体の調整速度が上がり、結果として画づくりが前に進みます。
回帰を完全に無くすのは難しいですが、壊れ方を局所化し、許容範囲を決め、継続できるテストに落とすと、ポストは触れる状態を保ちやすくなります。触れる状態を維持できることが、画づくりの継続性そのものです。
11. Three.jsポストプロセスの運用監視 本番で困らない設計
本番で重要なのは「速いか遅いか」より、遅くなったときに自動で落とせるか、原因を追えるかです。端末差が大きい以上、全端末で同じ構成を強制すると破綻します。プリセットとフォールバック、そしてログ設計が運用耐性を決めます。運用を前提にした設計があるだけで、ポストは「贅沢品」から「制御できる機能」へ変わります。
運用で困る場面は、性能悪化より「再現できない」ことが多いです。再現できる情報(構成・解像度・端末)を揃えると、改善は速くなります。
11.1 計測設計(FPSよりフレーム時間)
平均FPSだけだと揺れが見えません。p95のフレーム時間、内部解像度、DPR、有効パス一覧など、原因に繋がる情報を揃えると対策が早くなります。計測は最適化のためだけでなく、障害対応のために必要です。ユーザーの「重い」を再現できない最大要因は、環境情報とパイプライン情報が欠けていることです。最低限の情報があるだけで、切り分けは別物になります。
計測は増やしすぎると回らないため、意思決定に直結する指標に絞ります。「フレーム時間」「内部解像度」「プリセット」「有効パス」「renderer.info」程度でも、切り分けは一気に楽になります。完璧な計測より、継続できる計測が価値です。継続できる形に落とすほど、現場の運用は強くなります。
11.2 端末別プリセット設計
端末差を吸収する現実解は、プリセットを用意し、端末カテゴリで初期値を決めることです。モバイルはLow、ミドルはMed、ハイエンドはHigh、といった分け方で、ユーザーが変更できるようにするとサポートも楽になります。プリセットは「品質の自由度」ではなく「運用の再現性」を作る仕組みです。再現性があると、障害対応も改善も速くなります。
プリセット設計では、パスのオンオフと解像度戦略をセットで持ちます。SSAOを切るだけでなく内部解像度も落とす、といった組み合わせです。これにより、個別設定の組み合わせ爆発を避けられます。プリセットがあるだけで、本番運用の難易度は大きく下がります。さらに、プリセットは「品質の合意」を作るためにも使えます。
11.3 自動フォールバック(動的解像度、パス削減)
本番でのフォールバックは「自動で落とす」ことに価値があります。フレーム時間が一定以上悪化したら内部解像度を一段落とし、それでもダメならSSAOを切る、といった段階です。段階があると、体験を完全に壊さずに生存できます。これがないと、重い端末は離脱し、軽い端末だけが残る構造になります。フォールバックは最適化ではなく安定化の仕組みです。
頻繁に上下すると不安定になるため、クールダウンとヒステリシスを入れます。段階を増やしすぎず、数段階に絞る方が運用しやすいです。保険があるだけで、表現の挑戦がしやすくなる副次効果もあります。止血手段を持った上で挑戦できる状態が、本番での持続可能性を上げます。
export function maybeDegrade(
avgFrameMs: number,
state: { internalScale: number; ssaoOn: boolean },
cooldown: { until: number }
) {
const now = performance.now()
if (now < cooldown.until) return state
const next = { ...state }
if (avgFrameMs > 28 && next.internalScale > 0.85) {
next.internalScale = 0.85
cooldown.until = now + 3000
} else if (avgFrameMs > 32 && next.internalScale > 0.7) {
next.internalScale = 0.7
cooldown.until = now + 3000
} else if (avgFrameMs > 36 && next.ssaoOn) {
next.ssaoOn = false
cooldown.until = now + 5000
}
return next
}
11.4 障害報告に耐えるログ設計
障害報告で欲しいのは、GPU/ブラウザ/解像度/DPR/有効パス一覧です。これがないと再現に時間が溶けます。個人情報に配慮しつつ、技術情報は収集する必要があります。最低でも「DPR」「内部解像度」「プリセット」「有効パス」「renderer.info」程度があると切り分けが可能になります。ログがあるだけで「直せる」確率が上がります。
ログは量より構造が重要です。初期化ステップやパス構成をコード化しておくと、サポート側が症状を分類しやすくなり、開発側が優先順位を付けやすくなります。運用監視は後付けにすると入りにくいので、最小限だけでも早めに入れる価値があります。運用の基盤があるほど、ポストは本番で長く生き残ります。
運用を前提にすると、ポストプロセスは「豪華にするほど不安定」ではなく「段階とフォールバックがあるほど安定」になります。計測とログと段階設計が揃うほど、本番での意思決定が短くなります。
12. Three.jsポストプロセス導入ロードマップ
ポストプロセスは、導入順序を誤ると「盛ったが壊れた」で終わりがちです。戻れる基準線を作り、段階的に広げる方が成功しやすくなります。導入の進め方自体が運用設計の一部であり、最小構成の固定、深度前提の整備、演出の段階化、標準パイプラインの合意が揃うほど、長期的に育てられる構成になります。
導入は技術判断だけでなく、チームの調整コストにも影響します。比較可能な基準線があるほど合意が速くなり、結果として導入が速くなります。
12.1 最小構成から始める(RenderPass+AA)
最小構成は、RenderPass+AA(FXAAなど)程度で固定します。この段階で、リサイズ、DPR上限、内部スケール、ログ、可視化の骨格を入れておくと、その後のパス追加が安全になります。最小構成が性能の基準点にもなるため、追加パスのコストが測れます。基準点がないと、重くなった理由が曖昧になり、対策が場当たりになります。基準点は「戻れる場所」であり、実務では最も強い保険になります。
最小構成は「画づくりの基準線」でもあります。基準線があると、後から入れたBloomやSSAOの効果が比較でき、調整が収束しやすくなります。基準線がないと、何が良くなったのか、何が悪くなったのかが曖昧になり、議論が感覚論になります。基準線を固定するだけで、導入は「盛る」から「育てる」へ変わります。
12.2 深度系を追加するタイミング
深度系(SSAO/DOF)は、near/far、透明物、DepthTextureの前提を整理してから入れます。前提が固まっていない状態で入れると、ノイズや破綻の調整に時間が溶け、結局オフにされがちです。深度可視化を用意し、解像度更新が漏れないことを確認してから導入すると、調整が収束します。深度系は「入れる前の準備」で成否が決まると言っても過言ではありません。
深度系は土台を変えるため、演出系より先に入れると調整が安定することが多いです。逆に演出を先に盛ってから深度系を入れると、見た目の揺れが大きくなり、合意形成が難しくなります。導入順序は見た目だけでなく、チームの調整コストも左右します。順序を設計できると、結果として導入が速くなります。
12.3 演出系を積む順番と撤去容易性
演出系は「入れる」より「撤去できる」構造が重要です。Bloomは低解像度でコストを落としやすく、効果も分かりやすいので、最初の演出として扱いやすいです。DOFやSSGIのように前提とコストが重いものは最後に回し、必要性が明確になってから投資します。撤去できる構造があると、試せる回数が増え、結果として良い画に到達しやすくなります。試行回数は、表現力の源泉です。
演出系はプリセットとフラグで切れる形にし、最大構成が常に走らないようにします。重い演出はHighだけに入れ、Low/Medは軽量化する、といった段階があると、本番での端末差にも耐えられます。演出は「最大」より「段階」が運用を救います。段階があると、演出の価値を守りながら現実的に配布できます。
12.4 標準パイプライン固定と運用合意
標準パイプライン(デフォルト順序と設定)を固定し、チーム内で合意すると、順序と数値が揺れにくくなり回帰が減ります。合意がないと、順序と数値が揺れて調整が終わらず、結局固定値として触れなくなることが多いです。標準があると変更はレビュー対象になり、意図と影響が揃った状態で改善できます。自由度が高いほど事故が増えるため、自由度より合意が重要になります。
合意の対象は「見た目」だけではなく「落とす順序」も含みます。重くなったときに内部解像度を落とすのか、SSAOを切るのか、Bloomを弱めるのかが決まっていると運用が迷いません。標準パイプラインは画づくりの仕様であると同時に、運用の仕様でもあります。合意が揃うほど、ポストは本番で長く生き残ります。
導入を段階化し、基準線と合意を持つと、ポストプロセスは「盛って壊れる」から「育てて守る」へ変わります。育てられる構成は、長期的に見た目の競争力を支えます。
おわりに
ポストプロセスを安定させる鍵は、エフェクトの「良し悪し」ではなく、パス連鎖の前提を揃えて順序を固定することです。線形/sRGB、トーンマッピングの位置、深度の扱い、UI合成の責務が曖昧なままだと、数値調整が効かない破綻に入りやすくなります。逆に、前提が固定されるだけで同じ設定の意味が一定になり、比較が可能になって調整が収束しやすくなります。
EffectComposerは、見た目を作る道具であると同時に「中間バッファの受け渡しを管理する実行基盤」です。ping-pongの流れが追えると、真っ黒になる、出力が消える、リサイズで崩れるといった事故が「どこで壊れたか」へ分解できるようになります。深度依存パスは特に、前提(near/far、透明物、解像度一致)を固めてから入れるほど成功率が上がり、ノイズ対策としてのサンプル増加に逃げにくくなります。
性能は、最終的には解像度設計が支配します。DPRの上限、内部解像度の段階、パス別解像度、ブラー系の低解像度化を「後から」足すのではなく、最初から逃げ道として持つと、品質を保ったまま軽くできます。重くなったときに落とす順序が決まっているほど、連鎖的な悪化(SSAO→サンプル増→内部解像度低下→AA強化→UI滲み)のような迷走を止めやすくなります。
長期運用で差が出るのはコード構造と運用設計です。パス生成を設定から分離し、依存関係を宣言し、デバッグ可視化と有効パス一覧のログを持つだけで、追加・撤去・回帰防止が現実的になります。プリセットとフォールバックがある構成は、本番で「止められる」安心感があり、結果として表現の挑戦も続けやすくなります。ポストを育てられる状態を作ることが、最終的に画づくりの速度そのものになります。
EN
JP
KR