チャンネルパッキング戦略|UE/Unityのテクスチャを軽くする設計

PBR(物理ベースレンダリング)ワークフローでは、Roughness(表面の粗さ)・Metallic(金属度)・AO(Ambient Occlusion=くぼみの陰影)のグレースケール情報を1枚ずつ書き出すと、すぐにテクスチャ枚数が膨れます。しかし、これらはどれも1チャンネルあれば足りる情報。ならば1枚にまとめて詰めてしまえばいい、という発想がチャンネルパッキングです。

本記事では、パッキングが何のためにあるのか、UE と Unity の標準規約、圧縮形式との相性、自プロジェクト規約と Substance Painter の出力テンプレート設計までを、現場で「次のアセット規約どうする?」と聞かれたときに即答できる粒度で整理します。

夕宮たいだ

ふぁ……みんな〜、今日はテクスチャを軽くする話だよぉ。1枚に複数のグレースケールを詰め込んじゃう発想なんだぁ。一緒にいこ〜。

目次

1. チャンネルパッキングって何だっけ

ひとことで:1枚のテクスチャの R/G/B/A 各チャンネルに、別々のグレースケール情報を詰め込む手法です。

通常のテクスチャは、1枚で R / G / B / A の4チャンネルを持っています。普段は色のため3チャンネルを束ねて使い、A は透過情報に当てるのが一般的です。

しかし、PBR の Roughness・Metallic・AO はもともとグレースケール(1チャンネルあれば足りる)です。これらを別ファイルにすると、1枚あたり4チャンネルの容量を確保しながら実際は1チャンネルしか使わない非効率が生まれます。

そこで3つのグレースケール情報を R/G/B にそれぞれ詰め直して1枚にまとめる、というのが基本アイデアです。下図のように、1枚の RGBA テクスチャは4枚分のグレースケールを運べる「4車線の道路」と捉え直せます。

RGBAテクスチャがR/G/B/Aの4チャンネルのグレースケール情報に分解される概念図
図1:1枚のRGBAテクスチャは4チャンネル分のグレースケール情報を運べる

2. なぜパックするのか

ひとことで:メモリ・サンプル数・読み込み速度のすべてに効くからです。

  • メモリ削減:別々の3枚にすると 12 チャンネル分の容量を確保することになりますが、1枚にパックすれば 4 チャンネル分で済みます。VRAM(グラフィックボード上のメモリ)常駐量が直接減ります。
  • サンプル数の削減:シェーダー内のテクスチャサンプリング(テクスチャから値を読み出す処理)回数はコストに直結します。3回が1回に減れば、レジスタ圧迫(GPUの一時記憶領域の使いすぎ)もキャッシュミス(高速メモリにヒットしない状態)も軽減されます。
  • ロード時間と管理コスト:枚数が減ると I/O(ストレージ読み書き)回数とメタデータ管理のオーバーヘッドが下がります。

ただし、後述する sRGB と Linear の取り違えや、圧縮形式との相性を間違えると見た目を直接損ないます。「とりあえず詰めればいい」ではなく、規約として整理して使うのが前提です。

3. UE の標準:ORM

ひとことで:Occlusion / Roughness / Metallic を R/G/B に並べる、Unreal Engine の事実上の標準です。

Unreal Engine で最も広く使われている規約が ORM です。R に Ambient Occlusion、G に Roughness、B に Metallic を入れた1枚を指します。UE 標準のアセットは、おおむね次の3枚構成で運用されます。

マップ内容色空間
BaseColor物体の色sRGB
ORMR=AO / G=Roughness / B=MetallicLinear
Normal法線(タンジェント空間)Linear(BC5)

3枚で1セットと決め切れるとアセット管理が楽になります。Material Editor 内では ORM から Component Mask(特定チャンネルだけを抜き出すノード)(R)/(G)/(B)で取り出し、Roughness/Metallic/AO の入力ピンに繋ぐのが典型パターンです。並び順は絶対の規約ではなく Epic Games(Unreal Engine の開発元)の慣習が広まったものですが、Marketplace(Unreal の有料・無料アセット流通サイト)アセットの流用を考えると、独自順にする旨味はほぼなく、揃えておくのが無難です。

夕宮たいだ

ほえ〜、BaseColor と Normal と ORM、3枚で済むんだぁ。これだけ揃えとけば、たいていのアセットはまわるってことだねぇ。

ORMテクスチャのチャンネル割り当て。R=AO / G=Roughness / B=Metallic
図2:UE 標準の ORM パッキング規約

4. Unity の標準:Mask Map

ひとことで:HDRP は4チャンネル全部使う Mask Map、URP はもう少しシンプル、と覚えます。

Unity はパイプライン(描画系統。HDRP=High Definition Render Pipeline は据え置き機・PC向け高品質、URP=Universal Render Pipeline はモバイル含む汎用版)によってパッキング規約が異なります。

HDRP の Mask Map

HDRP の Lit シェーダーが要求する規約は、4チャンネルすべてを使い切るものです。

チャンネル内容
RMetallic
GAmbient Occlusion
BDetail Mask
ASmoothness

注意点はふたつ。ひとつは、UE の ORM と並び順が違うこと。R が Metallic、G が AO で、UE と入れ替わっています。両エンジン併用のスタジオでは混同して破綻させがちです。もうひとつは、HDRP は Roughness ではなく Smoothness(= 1 – Roughness)を扱う点。Painter 側は Roughness で作業しているので、エクスポート時に反転を挟むのが定石です。

URP のシンプルパック

URP の Lit シェーダーは入力が少なめで、Metallic Smoothness マップ(R に Metallic、A に Smoothness、G/B は未使用または別用途)が標準です。AO は別テクスチャとして渡すのが基本で、Mask Map のような全部入りパッキングではありません。

下図のように、UE の ORM と Unity HDRP の Mask Map を並べると、割当の違いが一目でわかります。

UEのORMとUnity HDRPのMask Mapのチャンネル割り当て比較
図3:UE ORM と Unity HDRP Mask Map のチャンネル割当の違い

5. 圧縮形式と相性:BC1〜BC7/ASTC

ひとことで:BC1 はカラー、BC5 はノーマル、BC7 は高品質汎用、ASTC はモバイル、と用途で分かれます。

パッキングは、最終的にどの圧縮形式に通すかとセットで設計します。形式によって扱えるチャンネル数や品質特性が違うためです。

Block Compression(BCn)の早見

PC・コンソール向けの代表的な BC 形式は次の通りです。

  • BC1(DXT1):RGB 用、最軽量、アルファは 1bit のみ。アルファ不要の BaseColor や低重要度の小物に。
  • BC3(DXT5):RGBA、アルファ 8bit。アルファを使う BaseColor 向け。容量は BC1 の2倍。
  • BC4:1チャンネル専用。Roughness や Height の単体書き出しに最適。
  • BC5:2チャンネル(XY)専用。ノーマルマップの定番。Z は GPU 側で再構成するためデータは XY のみで足ります。
  • BC6H:HDR 環境マップ用。
  • BC7:4チャンネル高品質。容量は BC1 の2倍ですが品質劣化が目立ちにくく、ORM や Mask Map など滑らかなグラデーションが必要なパックドテクスチャに向きます。

ORM や Mask Map は3〜4チャンネルすべてが独立した情報を持つため、BC1 ではブロック単位の色破綻が Roughness 段差として浮きます。パックドは BC7 が第一候補 です。

BC1/BC3/BC4/BC5/BC7/ASTCの圧縮形式と用途の早見表
図4:圧縮形式の用途別早見

ASTC:モバイル向け

ASTC(Adaptive Scalable Texture Compression)は、モバイルや一部コンソールで採用される形式です。ブロックサイズを 4x412x12 で選べる柔軟性があり、品質と容量のトレードオフを細かく調整できます。モバイル向けでは BC 系の代わりに ASTC を選びます。

色空間:sRGB と Linear の取り扱い

Roughness や Metallic は 線形空間(Linear)の値 として扱います。同じテクスチャに sRGB(モニター表示用に明るさを補正した色空間)と Linear(補正なしの素のままの値)を混ぜると、サンプリング時にガンマ補正(明るさのカーブ調整。本来は色用の処理)がかかって Roughness 値が歪みます。ORM や Mask Map は エンジン上で Linear(sRGB オフ)として扱う設定 を必ず行ってください。体系的な解説は CR-12 DCC→エンジンの色合わせ(リニア・sRGB・色空間) を参照してください。

夕宮たいだ

うぐぅ……BC1 とか BC5 とか BC7 とか、似た名前ばっかりで、むずかしいねぇ。とりあえず「ORM は BC7」「ノーマルは BC5」って覚えとけばいいのかなぁ。

6. 自プロジェクト用テンプレートの設計

ひとことで:チャンネル割当・命名規則・色空間設定を、ドキュメントに書き切ります。

UE の ORM や Unity HDRP の Mask Map をそのまま採用するのが最短ですが、独自規約を作ることもあります。設計時に決めるべき観点は次の3つです。

チャンネル割当

R/G/B/A のどこに何を入れるか。AO・Roughness・Metallic・Smoothness・Detail Mask・Emissive Mask などから必要なものを選んで割り当てます。空きチャンネルの使い道はプロジェクトでよく使うエフェクト次第です。

命名規則

ファイル名サフィックスでパッキング規約を判別できるようにすると、ロード時の自動設定(色空間・圧縮形式)をスクリプトで処理できます。例:_BC(BaseColor)/_ORM(UE パック)/_MSK(Unity Mask Map)/_N(Normal)/_E(Emissive)。Painter のテンプレ名やエンジン側の Importer 設定にも揃えるのが理想です。

色空間設定

「BaseColor だけ sRGB、それ以外は Linear」を例外なく言い切ってしまうと、運用ミスが激減します。

夕宮たいだ

ORM を sRGB のままパックしちゃダメだよ! Roughness の値がガンマで歪んじゃって、見た目がぜんぜん変わっちゃうんだぁ。ほんと、ダメだからね。

7. Painter での出力テンプレート作成

ひとことで:Output Template Editor に1回設定すれば、以後そのプロジェクトでは自動でパックされます。

Substance Painter には、ユーザー定義の出力テンプレートを作成する仕組みがあります。各レイヤーのチャンネルを、出力時に R/G/B のどこへ焼き込むかを GUI で組めます。

大まかな手順

1. Edit → Export Templates… を開く 2. 既存の Unreal Engine 4 (Packed) を複製してベースにする(最短ルート) 3. 出力ファイルごとに、RGB の各チャンネルへ Painter のチャンネル(Roughness・Metallic・AO など)を割り当てる 4. テンプレ名をプロジェクト規約に合わせる(例:MyGame_ORM_Standard) 5. テクスチャセット書き出し時にこのテンプレを選んで Export

下図のように、Output Template Editor では各出力ファイルの R/G/B/A スロットへ入力チャンネルをドラッグで割り当てます。

運用ノウハウ

  • 既存テンプレ(Unreal Engine 4 (Packed)Unity 5 / Unity 2017.x (Metallic Standard) など)を参考にすると、標準規約に合わせるのが速いです。
  • Smoothness が必要な Unity 向けでは、Roughness を反転(1 - Roughness)するノードを Output Template 内で噛ませます。
  • テンプレートは Painter 側のユーザー設定として保存されるので、チーム配布時はテンプレ JSON を Git 管理にすると事故が減ります。
夕宮たいだ

ほら、これ一回作っとくと、毎回手作業で詰め込まなくて済むんだよぉ。便利でしょ?

8. ハンズオン演習

ひとことで:Painter で ORM 用テンプレを1個作って、実際に書き出してみます。

1. 適当な PBR マテリアルを1テクスチャセット用意 2. Edit → Export Templates… から Unreal Engine 4 (Packed) を複製 3. ORM 出力ファイルの R に AO、G に Roughness、B に Metallic が割り当たっていることを確認 4. 名前を Practice_ORM などに変更して保存 5. File → Export Textures で Output Template にいま作ったものを選び、書き出し 6. 出力された ORM テクスチャを画像ビューアで開き、R/G/B 単独表示で AO/Roughness/Metallic がそれぞれ入っていることを確認

最後の R/G/B 単独確認は地味ですが、規約通りにパックされたかを目視できる唯一の手段です。新規テンプレを作ったら必ず1回は通す癖をつけてください。

9. チェックリスト

ひとことで:パックドテクスチャを書き出す前のセルフチェック項目です。

  • [ ] パッキング規約(UE ORM か Unity Mask Map か独自か)がプロジェクトで合意されている
  • [ ] R/G/B/A のどこに何が入るかをドキュメントで明文化している
  • [ ] エンジン側で Linear(sRGB オフ)に設定している
  • [ ] 圧縮形式が用途に合っている(パックドは BC7 / ノーマルは BC5 / モバイルは ASTC)
  • [ ] ファイル名サフィックスが規約通りになっている
  • [ ] Painter の Output Template が作成済みで、チームで共有されている
  • [ ] AO を BaseColor に焼き込んでいない(パックド側で運用)
  • [ ] Unity 向けの場合、Roughness → Smoothness の反転処理が入っている

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

ひとことで:色空間取り違え・AOの二重適用・規約バラバラ・圧縮選択ミス、が定番です。

sRGB と Linear の取り違え

ORM や Mask Map をエンジンで sRGB として読み込むと、Roughness 値にガンマ補正がかかり、想定より滑らかに見えたりザラついて見えたりします。Texture Importer で sRGB チェックを外すのを忘れない、が鉄則です。

AO を BaseColor に焼き込んでしまう

旧世代の手法では BaseColor に AO を焼き込むこともありましたが、PBR では原則 NG。ライティング側でも AO を適用するため二重にかかって暗くなりすぎます。AO はパックドテクスチャ側で持ち、エンジンの該当ピンに接続して運用します。

プロジェクト内で規約がバラバラ

UE と Unity を併用するスタジオで起きがちな事故です。アーティストごとに ORM だったり Mask Map だったりするとマテリアル処理が分岐して破綻します。プロジェクト立ち上げ時に1つに決め、ファイル名サフィックスで区別できるようにします。

圧縮形式の選択ミス

ORM を BC1 で圧縮して段差が浮く、ノーマルを BC1 で圧縮して Z 復元前提が崩れる、といった事故も定番です。「パックドは BC7、ノーマルは BC5」を最初に共有しておくだけで大半は防げます。容量が厳しい局面でも、圧縮率の数値だけで決めず、必ず最終的な見た目で判断してください。

夕宮たいだ

ふぁ……これでチャンネルパッキングの全体像はOK……かなぁ。色空間と Painter の話は、別の記事でもう少し詳しくやるねぇ。

11. 次に読む記事

ひとことで:パッキングを支える色空間とノーマルマップ、Painter 側のテンプレ運用に進みます。

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

この記事を書いた人

目次