HDRとトーンマッピング
白飛びやのっぺりした画を根絶。上限のないリニアHDRを露出とトーンマッピングで表示レンジへ写す原理、Reinhard と ACES の違い、ブルームの正しい順序まで理解できます。
- 1.HDRレンダリングは光源やハイライトが 1.0 を超える放射輝度を持つため、上限のない浮動小数点(fp16 など)でリニアに計算し、最終段でレンジ圧縮して表示レンジへ写す。
- 2.露出はトーンマッピングの前に掛ける線形スケールで「どの輝度を中間グレーに置くか」を決め、トーンマッピング演算子(Reinhard・ACES)は高輝度をなだらかに丸める非線形曲線として役割が分かれる。
- 3.ブルームは高輝度部だけを抽出してぼかし加算する光学の再現で、トーンマッピングとエンコード(ガンマ/PQ)の順序を守らないと輝度関係が崩れる。
リニアに計算すると値は 0〜1 に収まらない
物理的に正しくライティングを積分すると、結果の放射輝度は 0〜1 の範囲に収まりません。太陽の反射ハイライト、電球のフィラメント、金属の鏡面反射は、拡散面の何十倍〜何千倍もの輝度を持ちます。実世界の輝度は夜空の星から真昼の太陽まで十数桁にわたり、この広さをダイナミックレンジと呼びます。
したがって現代のレンダラは、内部バッファを 8 ビット整数ではなく**上限のない浮動小数点フォーマット(16 ビット半精度の RGBA16F や、パック浮動小数点の R11G11B10F など)**で持ち、1.0 を超える値をそのまま保持します。これが HDR(High Dynamic Range)レンダリングです。ライティングの物理的正しさを担保する /graphics/shading-models-phong-pbr/ や、多重反射で自然に高輝度が生じる /graphics/path-tracing-global-illumination/ は、いずれも出力がこの HDR 領域に広がることを前提にしています。問題は、この青天井のレンジを、たかだか数百ニト・8 ビットの表示装置へどう写すかです。
なぜ単純なクリップではだめか
最も素朴な方法は、1.0 を超えた値を頭打ち(クリップ)することです。しかしこれは致命的に情報を失います。空・雲・ハイライトのように輝度が 1.0 を超える領域がすべて真っ白の一色に潰れ、そこにあったディテールと色が消えます。逆に露出を下げてクリップを避けると、今度は暗部が黒く沈みます。
クリップ(naive): out = min(1.0, hdr) ← 1.0 超が全部同じ白に潰れる
→ハイライトのディテール・色相が失われ「白飛び」
トーンマッピング: out = f(hdr) ← f は単調増加のなだらかな圧縮曲線
→高輝度ほど強く圧縮、暗部・中間部の階調は保つ
本質的な難しさは、桁違いに広い入力レンジを、狭い出力レンジ 0〜1 へ非線形かつ単調に押し込む必要がある点です。人間の視覚も網膜で対数的な圧縮を行っており、それを模した滑らかな S 字ないし飽和曲線を使います。この曲線がトーンマッピング演算子です。
露出とトーンマッピングは役割が違う
ここで多くの実装が混同する 2 段階を厳密に分けます。露出(exposure)はトーンマッピング曲線に入れる前に掛ける線形なスケール係数です。カメラの絞り・シャッター・ISO に相当し、「シーンのどの輝度帯を中間グレー付近に置くか」を決めます。一方トーンマッピングは、露出調整後の値を表示レンジへ丸める非線形変換です。
| 段 | 変換の性質 | 決めること | 対応するカメラ操作 |
|---|---|---|---|
| 露出 | 線形スケール(乗算) | どの輝度を基準(中間グレー)に置くか | 絞り・シャッター速度・ISO |
| トーンマッピング | 非線形な圧縮曲線 | 高輝度をどうなだらかに丸めるか | フィルムの特性曲線・現像 |
順序が重要です。まず露出でシーン全体を線形にスケールし、その後トーンマッピング曲線を通します。露出を「明るさスライダー」としてトーンマッピング後に足し引きすると、曲線の膝(ニー)位置がずれて破綻します。露出は必ず曲線の手前です。自動露出(オートエクスポージャ)では、直前フレームの平均輝度(対数平均)をヒストグラムや縮小バッファから求め、目標の中間グレーへ合わせるスケールを算出し、急変を避けるため時間方向に緩やかに追従(適応)させます。
HDRポストプロセスの並び(順序が結果を決める):
リニアHDR(範囲無制限, fp16)
→ 露出を乗算 exposed = hdr × exposureScale
→ トーンマッピング mapped = tonemap(exposed) // 0〜1 の表示リニア
→ エンコード(ガンマ) out = encode_sRGB(mapped)
→ 8ビット出力
鉄則: トーンマッピングは必ずエンコード(ガンマ)より前。
先にガンマを掛けてから圧縮すると輝度関係が崩れる。
Reinhard 演算子 ── 素直な飽和曲線
最も基本的な演算子が Reinhard です。原理は単純で、大きい値ほど強く圧縮する双曲線型の飽和関数です。
Reinhard(最も単純な形):
out = x / (1 + x)
x が小さい(暗部) → out ≒ x (ほぼ素通り=線形)
x が大きい(高輝度) → out → 1 (1 に漸近するが到達しない)
拡張形(白飛び基準 Lwhite を指定):
out = x × (1 + x / Lwhite²) / (1 + x)
x / (1 + x) は暗部では傾き 1 でほぼ線形に振る舞い、高輝度では 1 へ漸近して決してクリップしません。これによりハイライトが真っ白に潰れず、階調が残ります。実装が軽く挙動が読みやすい一方、中間調がやや眠く(コントラストが低く)なり、色が浅く見えがちなのが弱点です。フィルムのようなくっきりしたコントラストは得にくく、映像制作の最終ルックにはあまり使われません。
Reinhard を RGB 各チャネルに独立適用すると、彩度の高い高輝度部で色相がずれます。1 チャネルだけ先に飽和すると色バランスが変わるためです。輝度(luminance)を計算してその比率だけを圧縮し、色差を保つ「輝度ベース」の適用にすると色相は安定しますが、逆に強いハイライトが白へ抜けにくくなり不自然になることもあります。どちらが正解かはルック次第で、ACES 系はこの折り合いを曲線設計側で吸収しています。
ACES ── フィルム的な S 字と広色域の標準
映画・ゲームで事実上の標準になったのが ACES(Academy Color Encoding System)由来のトーンマッピングです。Reinhard との最大の違いは、単なる飽和ではなくフィルムの特性曲線を模した S 字である点です。暗部を軽く持ち上げ、中間調のコントラストを立て、高輝度をなだらかに丸めます。この「膝と肩(shoulder)」を持つ形が、写実的で締まったルックを生みます。
ACES フィルミック近似(Narkowicz, RGB 各成分に適用する軽量版):
a=2.51 b=0.03 c=2.43 d=0.59 e=0.14
out = clamp( (x·(a·x + b)) / (x·(c·x + d) + e), 0, 1 )
・分子分母とも x の二次式 → S 字(暗部やや持ち上げ+高輝度で肩)
・実際の ACES は色空間変換込みのより厳密なパイプラインで、
これはその見た目を近似した簡易式
ここで注意すべきは、本来の ACES はトーンマッピング「曲線」だけを指すのではないことです。ACES は入力(IDT)→作業色空間 ACEScg(Rec.2020 より広い色域)→ルック変換(RRT)→出力変換(ODT)までを含む色管理の枠組みで、トーンマッピングはその一部です。広い色域で計算し最後に出力デバイスへ変換するため、色の破綻が少なくデバイス非依存になります。色域(表現できる色の範囲)と伝達関数(明るさの符号化)が独立した別軸であることは /graphics/color-spaces-gamma/ で詳述しています。
| 演算子 | 曲線の性質 | 得意 | 弱点 |
|---|---|---|---|
| Reinhard | 双曲線の単純飽和 | 軽量・挙動が読みやすい | 中間調が眠く色が浅い |
| ACES(フィルミック) | S字(膝+肩) | 締まった写実的ルック・広色域管理 | 計算がやや重く、味付けが強い |
| Uncharted2/AgX 等 | 調整可能なフィルミック曲線 | アーティストが膝・肩を制御 | パラメータ調整の習熟が要る |
ブルームは「光学のにじみ」の再現
**ブルーム(bloom)**は、非常に明るい光源の周囲が淡く光ってにじむ現象で、レンズやカメラセンサ、人間の目の内部散乱で実際に起きる光学効果です。HDR だからこそ正しく再現できます。理由は、しきい値を超える高輝度部だけを抽出する必要があるからで、1.0 で頭打ちの LDR ではその「1.0 を超えた分」の情報が既に失われているためです。
ブルームの標準的な流れ:
1. 抽出: bright = max(0, hdr − threshold) // 高輝度部だけ取り出す
2. ぼかし: 縮小バッファ(ミップ階層)で複数半径のガウシアンぼかし
3. 加算: result = hdr + bloomStrength × blurredBright // 加算合成
4. その後にトーンマッピング → エンコード
ぼかしは負荷が高いので、フル解像度ではなく段階的に縮小した
複数解像度でぼかして合成し、広がりと軽さを両立する。
決定的なのは順序です。ブルームの抽出・加算はトーンマッピングより前に、リニアHDR空間で行います。トーンマッピングで圧縮した後の値からしきい値抽出すると、既に高輝度が丸められているため正しく光源を分離できません。加算合成なのも物理的な理由があり、光は線形に足し合わさるからです(/graphics/color-spaces-gamma/ のリニアワークフローの原則)。ブルームやトーンマッピングを含むこうした画面全体の後処理は、G バッファ描画後の画面空間パスとして走らせるのが一般的で、パイプライン上の位置づけは /graphics/forward-deferred-rendering/ の後段処理と共通します。
露出以外のトーンマッピング+色補正(カラーグレーディング)は、入力色から出力色への写像であり、実行時に毎回曲線を計算する代わりに 3D LUT(例 32×32×32 の色立方体)に事前計算して焼き込めます。シェーダは HDR 値を対数などでエンコードして LUT を 3D テクスチャとして 1 回サンプリングするだけで済み、複雑なグレーディングでも一定コストになります。アーティストが調整した最終ルックをそのまま LUT 化できるのも利点です。
「HDR レンダリング」と「HDR ディスプレイ出力」を混同しないこと。前者は表示装置によらず内部計算を高ダイナミックレンジで行う話で、SDR 画面にも必要です。後者は HDR10 等の表示装置へ出す話で、その場合エンコードは sRGB ではなく PQ(ST 2084、絶対輝度を最大1万ニトまで符号化)や HLG を使い、トーンマッピングの目標レンジ自体が広がります。「トーンマッピングは露出の後・エンコードの前」「ブルーム抽出はトーンマッピングの前」という順序も頻出です。
まとめ
- HDR レンダリングは光源やハイライトが
1.0を超えるため、内部を上限のない浮動小数点でリニアに計算し、最終段で表示レンジへ写す。単純クリップは高輝度を白へ潰し情報を失う。 - **露出は線形スケール(曲線の手前)**で基準輝度を決め、トーンマッピングは非線形曲線で高輝度を丸める。両者は役割が分かれ、順序を守る。
- Reinhard は軽量な飽和曲線だが中間調が眠い。ACES はフィルム的 S 字+広色域(ACEScg)管理で締まった写実ルックを与え、映像・ゲームの標準。
- ブルームは高輝度部を抽出してぼかし加算する光学再現で、抽出・加算はトーンマッピングより前のリニアHDR空間で行う。
- 順序の鉄則は「露出 → トーンマッピング → エンコード(sRGB/PQ)」。HDR 表示では sRGB でなく PQ/HLG を使い、目標レンジ自体が広がる。
グラフィックス Article
HDRとトーンマッピングを実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
HDR
比較で見る軸
難易度: advanced / カテゴリ: グラフィックス / タグ数: 6
導入後に効く点
露出はトーンマッピングの前に掛ける線形スケールで「どの輝度を中間グレーに置くか」を決め、トーンマッピング演算子(Reinhard・ACES)は高輝度をなだらかに丸める非線形曲線として役割が分かれる。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- グラフィックス
- タグ数
- 6
判断チェックリスト
- 自社の用途が「HDR / トーンマッピング」に近いか確認する。
- 強みである「HDRレンダリングは光源やハイライトが 1.0 を超える放射輝度を持つため、上限のない浮動小数点(fp16 など)でリニアに計算し、最終段でレンジ圧縮して表示レンジへ写す。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。