DCC→エンジンの色合わせ|リニア・sRGB・色空間の実務

Substance Painter で見たときは赤味の効いた良い色だったのに、Unreal や Unity で開いたら妙にくすんで見える──こうした「色がズレる」事故は、ほぼ例外なく 色空間(リニア / sRGB)の取り違え が原因です。

本記事では、リニアと sRGB の違い、テクスチャ種別ごとの色空間の使い分け、DCC とエンジンのデフォルト挙動、そしてトーンマッピングの影響までを、現場で「色合わせのトラブルを切り分けられる」粒度で整理します。前提として PBR の理論(CR-01) を読んでおくと、リニア計算が必要な理由が腑に落ちやすくなります。

夕宮たいだ

ふぁ……みんな〜、色がズレる事故、現場でほんとよく見るんだぁ。今日は「リニア・sRGB・トーンマッピング」をいっしょに整理していこ〜。

目次

1. なぜ色がズレるのか

ひとことで:色の符号化(sRGB / リニア)と計算空間(リニア)の取り違えが、ほぼすべての原因です。

色がズレる現象を分解すると、登場人物は次の3者です。

  • 画像ファイル:JPG / PNG は標準で sRGB として保存されている
  • シェーダー計算:物理的に正しい結果を出すには、リニア空間 で行う必要がある
  • モニタ表示:最終的に sRGB 空間で出力する必要がある

DCC やエンジンは、この3者の間で「読み込み時にリニアへ変換するか」「表示時に sRGB に戻すか」を自動的に処理してくれます。ただし、デフォルト挙動と設定 UI が DCC ごとに違う ため、ここで取り違えが発生します。

2. ガンマと sRGB の正体

ひとことで:人間の目の暗部に敏感な特性を、効率的に符号化したカーブです。

ガンマ 2.2 の歴史的背景

ガンマ 2.2 は、もともと CRT モニタの応答特性 から来ています。電圧を倍にしても光量が倍にならない、というハード由来のクセです。偶然にも、これが 人間の目が暗部に敏感 な特性とよく合っていたため、限られた 8 ビット(256 段階)の階調を「人間が違いを感じやすい暗部」に厚く配分する符号化として標準化されました。

sRGB

1996 年に標準化された色空間で、ガンマ 2.2 をベースにした「画像保存用」の規格です。現代の JPG / PNG は事実上すべて sRGB です。下図のように、入力値(記録値)と出力値(実際の明るさ)の関係が カーブ になっています。

リニアとsRGBのカーブの違いを示す図
図1:sRGBは暗部に階調を多く割り当てる保存用カーブ
夕宮たいだ

うぐぅ……ガンマ 2.2 ってむずかしいねぇ。でもね、要は「目の特性に合わせた省エネ符号化」って思っとけば、本筋は外さないよぉ。

3. リニアワークフローの全貌

ひとことで:「読み込み時にリニア化、表示前に sRGB 化」が原則です。

シェーダーがやりたい計算は、たとえばランバート反射(CR-02)の dot(N, L) です。「光が2倍なら結果も2倍」が成り立つ世界、つまり リニア空間 で計算する必要があります。sRGB のまま計算すると、「2倍に見える明るさ」と「数値の2倍」がズレ、PBR の物理的整合性が崩れます。

そこで、現代のレンダリングは リニアワークフロー で組まれています。下図のような流れです。

sRGBテクスチャをリニア化してシェーダー計算し、表示時にsRGBへ戻す流れ
図2:入口でリニア化し、出口で sRGB に戻す

1. テクスチャ読み込み(sRGB → リニア変換) 2. シェーダー計算(リニア空間で実行) 3. ポストプロセス(リニア HDR のまま) 4. トーンマッピング(HDR → LDR、まだリニア) 5. 表示(リニア → sRGB 変換、モニタへ送出)

入口でリニアにし、出口で sRGB に戻す」が標語です。途中の計算はすべてリニア、これだけ覚えておけば見通しが立ちます。逆に言えば、入口か出口のどちらかで変換が抜けると、画面の色は二度ガンマがかかった(または抜けた)状態になり、明らかに不自然な見え方になります。

4. テクスチャ別の色空間の使い分け

ひとことで:「色」は sRGB、「データ」はリニアで扱います。

PBR で扱うテクスチャを色空間で整理します。

BaseColorやNormalなどテクスチャ種類ごとのsRGBとLinearの使い分け
図3:色は sRGB、数値データは Linear
テクスチャ種類色空間理由
BaseColor / AlbedosRGB人間の目で見た「色」を保存している
Normalリニア方向ベクトルの数値であり、色ではない
Metallicリニア0 か 1 を表す物理値
Roughnessリニア0〜1 の物理値、見た目の明るさではない
AOリニア暗くする倍率の数値
EmissivesRGB色(明るさが必要なら HDR 値で強度を別管理)

ノーマルマップが青〜紫っぽい見た目なのは、色として見せているのではなく、方向ベクトルの数値を RGB に詰めているだけ です。これを sRGB として読むと、変換カーブが効いて方向ベクトルが歪み、CR-04 の「面が暗い」「ノーマルの効きが弱い」事故になります。

夕宮たいだ

ほよ? 種類で違うんだぁ。「色は sRGB、数値はリニア」って覚えると、迷わないねぇ。

5. 各DCC のデフォルト挙動

ひとことで:DCC ごとに色空間の前提と設定 UI が違うので、初期に把握します。

Maya + Arnold

リニアワークフローが前提です。Render Settings で OCIO(OpenColorIO)プロファイル を選択し、テクスチャ単位で sRGB / リニアを指定します。Arnold 側でテクスチャタイプを認識して自動変換することも多く、明示指定とのダブルチェックが安全です。

Substance Painter

内部計算はリニア、ビューポートには sRGB に変換して表示しています。Texture Set のチャンネル設定で各マップの色空間を明示的に持っており、出力時にも「BaseColor は sRGB として」「Roughness はリニアとして」と書き出しテンプレートで分けて指定します。

Houdini

MPlay(プレビュー)は OCIO 設定に依存し、COP / VOP / Karma で色空間の扱いが微妙に異なります。Solaris(USD)では USD 側の colorSpace 属性が尊重されるため、USD ベースのワークフローではここを揃えるのが先です。

夕宮たいだ

ていねいに整理するねぇ。DCC ごとに UI も用語も違うけど、やってることは「読込時にリニア化、表示時に sRGB 化」で全部同じだよぉ。

6. UE / Unity の色設定

ひとことで:エンジン側で「リニアワークフロー」が有効になっているかが大前提です。

Unreal Engine

内部レンダリングは常にリニアです。テクスチャインポート時に sRGB チェックボックスで色空間を指定します。

  • BaseColor / Emissive:sRGB ON(sRGB → リニアに自動変換)
  • Normal / Metallic / Roughness / AO:sRGB OFF(リニアのまま使用)

加えて、ACES トーンマッピングがデフォルトで有効、Auto Exposure(Eye Adaptation)も有効です。色合わせ時は両方を一時的に OFF にして比較するのが定石です。

Unity

Project Settings → Player → Color SpaceLinear に設定する必要があります。Gamma 設定のままでは PBR の物理的整合性が崩れ、Roughness の効きや HDR ライティングの結果が想定外になります。テクスチャインポーターの「sRGB (Color Texture)」チェックで個別マップの扱いを管理します。トーンマッピングは HDRP / URP / Built-in で実装が異なるため、プロジェクトのレンダーパイプラインを確認してから合わせ込みに入ります。

7. トーンマッピングの影響

ひとことで:HDR の広い値域を、画面表示できる狭い値域に「圧縮」する非線形変換です。

リニア空間での明るさは、1.0 を超える HDR(High Dynamic Range:明暗の幅が広い表現)値を自由に持てます。空や太陽の反射は 100.0 でも 1000.0 でも構いません。一方、画面に出せるのは 0〜1 の LDR(Low Dynamic Range:通常モニタで表示できる明暗範囲)値です。そこで、明るい部分ほど強く圧縮するカーブをかけて、HDR を LDR に押し込めます。これがトーンマッピングです。

代表的なトーンマッパーは次のとおりです。

  • ACES:映画業界標準。コントラストが高め。UE デフォルト
  • Filmic:シネマティックな仕上がり、Blender / Unity HDRP でも採用
  • Reinhard:シンプル、初期のトーンマッピング
夕宮たいだ

ぁぅ……ここ、見落としやすいんだぁ。Painter で完璧な色を作っても、UE の ACES を通したら別物に見えること、ほんとよくあるんだよぉ。

Auto Exposure / Eye Adaptation

トーンマッピングと並んで、Auto Exposure(自動露出) も色合わせを難しくする要因です。暗いシーンを自動で明るく、明るいシーンを暗く調整する機能で、「同じテクスチャでも環境光で見え方が変わる」現象の正体です。色合わせを始めるときは 一旦 OFF にする のが鉄則です。

8. ハンズオン演習

ひとことで:BaseColor(sRGB)と Roughness(リニア)の取り違えを、実機で再現してみましょう。

1. Painter で適当なメッシュに BaseColor と Roughness を作成、書き出し 2. UE または Unity に両方インポート 3. Roughness を「sRGB ON」で意図的に間違えて読み込む 4. マテリアルに接続して結果を見る:Roughness の値が想定より小さく解釈され、ハイライトが強く・表面が滑らかに見える 5. Roughness を「sRGB OFF」に戻して、正しい結果と並べて比較

RoughnessをsRGB ONで読み込んだ場合とOFFで読み込んだ場合の見え方比較
図4:Roughness は sRGB OFF で読む

「sRGB として読むと、暗部側に圧縮されたカーブで解釈される」現象を、目で確認できます。一度体験しておくと、現場で「ハイライトが妙に強い」と感じたときに、最初に色空間設定を疑える反射神経が身につきます。

9. チェックリスト

ひとことで:色合わせ前のセルフチェック項目です。

  • [ ] エンジン側で Linear Color Space が有効になっている(Unity は Linear、UE はデフォルトでリニア)
  • [ ] BaseColor / Emissive は sRGB 読込
  • [ ] Normal / Metallic / Roughness / AO はリニア読込
  • [ ] DCC とエンジンで同じトーンマッパー設定で比較している
  • [ ] Auto Exposure / Eye Adaptation を OFF にして色比較している
  • [ ] OCIO 設定が DCC・エンジン間で齟齬がない
  • [ ] テクスチャ命名やサフィックス(_albedo _n _orm など)と sRGB 設定が連動している

10. よくある間違い・トラブルシュート

ひとことで:Roughness の sRGB 化・Normal の sRGB 化・トーンマッピング忘れ・色空間設定不一致、の4つが定番です。

Roughness を sRGB として読み込み

  • 症状:ハイライトが想定より強い、表面が想定より滑らかに見える
  • 対処:インポート設定で sRGB を OFF。チャンネルパッキングで ORM テクスチャを使う場合(CR-05)も、ORM 全体は sRGB OFF が正しい

Normal を sRGB として読み込み

  • 症状:凹凸の効きが弱い、ノーマルが浅く感じる
  • 対処:インポート設定で sRGB OFF。CR-04 のタンジェント問題(緑反転やスムージング不一致)と症状が似るので、まず色空間を疑う

DCC とエンジンで色空間設定が違う

  • 症状:DCC で正しく見える色が、エンジンで違う
  • 対処:両者の OCIO・トーンマッパー・Linear/Gamma 設定を揃える。プロジェクト初期に文書化するのが事故予防の一番

トーンマッピングを忘れて色合わせ開始

  • 症状:DCC のレンダラとエンジンで色が違う、と原因不明のまま延々追いかける
  • 対処:トーンマッパーを揃えるか、両者で一旦 OFF にして基準色を合わせ、その後トーンマッパーを ON で最終調整
夕宮たいだ

ふぁ……色合わせまわり、ハマりどころは出尽くしたかなぁ。次はライティング基礎やチャンネルパッキングに進めるよぉ。

11. 次に読む記事

ひとことで:色空間の知識を、ライティングとテクスチャ運用に繋げていきましょう。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

目次