本文へスキップ

ORM・マスクマップ パッカー · Unity・Godot・glTF向けチャンネルパック

AO・ラフネス・メタリックなどを、エンジンが読むチャンネルに入れます。プリセットごとにチャンネル順の根拠を示し、PNGはラボが直接書くので、アルファ0の下のバイトも残ります。

チャンネルパックとは、別々のグレーマップを、エンジンが読む順番どおりにPNG 1枚のR・G・B・Aへ入れることです。Unity HDRPのマスクマップはRメタリック・Gアンビエントオクルージョン・Bディテールマスク・Aスムースネス、Unity URPのチャンネルパックテクスチャはRメタリック・Gオクルージョン・Aスムースネス、glTF 2.0とGodot 4向けのORMはRオクルージョン・Gラフネス・Bメタリックです。同じサイズのグレーマップを4枚まで入れ、プリセットを選ぶかチャンネルを手動で割り当て、エンジンがラフネスではなくスムースネスを求めるチャンネルに「反転」を付けて…-mask.pngをダウンロードします。パック後のバイトは測定済みで、エンジンへの読み込みは実行していません。

テクスチャマップをドロップ(PNGはチャンネルのバイトをそのまま保持)
テクスチャラボを開く
ブラウザ内で処理し、ファイルはアップロードされません。
テクスチャラボ:CC0テクスチャから生成したノーマルマップとOpenGL/DirectXの規約表示
CC0アセット(ambientCG)を開いた実際のテクスチャラボ画面です。
出力
  • Channel PNGs測定確認· numpy
  • Normal map測定確認· numpy
  • Packed mask / ORM測定確認· Pillow
  • Engine import未検証

パッカーが各チャンネルを埋める仕組み

入力はテクセルごとに1つのグレー値として読まれます。Rec. 709の輝度、つまり0.2126 R + 0.7152 G + 0.0722 Bを丸めた値です。本物のグレーマップ(R = G = B)なら保存値とぴったり同じなので、グレーのバイトは変わらずチャンネルに入ります。色のある画像は輝度に混ぜられてしまい、データマップとしては望む結果になることはまずありません。

プリセットが決めるのは入力の行き先だけです。入力は入れた順に意味のあるチャンネルを埋め、配置が無視するチャンネルは0、使わないアルファは255で書くので、ファイルは不透明のままです。自動の反転はありません。Unityのスムースネスは1 − ラフネスなので、ラフネスマップを持っているならスムースネスのチャンネルで「反転」(255 − 値)を付けます。

ここではアルファもデータです。HDRP・URPのテクスチャではスムースネス0がアルファ0です。パッカーはCanvasではなく自前のエンコーダーで(32行ずつ)PNGを書くので、そうしたテクセルの下のメタリックやAOのバイトも残ります。入力はブラウザの画像デコーダーで読むため、透明度のあるファイルではなく普通のグレーPNGを入れてください。

データとして読み込みます。UnityのHDRPのページはマスクマップのsRGB (Color Texture)をオフにしTexture TypeをDefaultにするよう、URPのページはチャンネルパックテクスチャのsRGBをオフにするよう案内し、glTF 2.0はメタリックとラフネスの値をリニアと規定しています。

マスクマップ
Unity HDRPのパックテクスチャ。Rメタリック・G AO・Bディテールマスク・Aスムースネス。
ORM
R・G・Bにオクルージョン・ラフネス・メタリック。glTF 2.0の順で、GodotのORMMaterial3Dも同じです。
定数チャンネル
配置上マップが要らないため、全体を0か255で書いたチャンネル。
反転
255 − 値。1 − xの8ビット版で、ラフネスとスムースネスを相互に変換します。

例:同じ3枚のマップを3つの配置で

1テクセル分のグレーマップ3枚:AO 10、ラフネス 80、メタリック 220。割り当ての行はパッカーの表示形式です(数字 = 入れたファイル、⁻ = 反転)。

ORM (glTF 2.0, Godot 4)   ファイル: ao, roughness, metallic     R←1 · G←2 · B←3 · A←255   → (10, 80, 220, 255)
Unity HDRPマスクマップ    ファイル: metallic, ao, roughness     R←1 · G←2 · B←0 · A←3⁻    → (220, 10, 0, 175)
Unity URPパック           ファイル: metallic, ao, roughness     R←1 · G←2 · B←0 · A←3⁻    → (220, 10, 0, 175)

スムースネス = 255 − 80 = 175  (1 − 0.314 = 0.686)
ラボで測定:ORMプリセット (10, 80, 220, 255)、手動割り当て (220, 10, 80, 0)、R反転 (245, 80, 220, 255)

ディテールマスクがないので、HDRPとURPの行は同じです。HDRPはBをディテールマスクとして読み、URPは無視します。HDRPプリセットにファイルを3枚だけ入れると3枚目がBに入るため、上のようにBを0に、Aを3番のファイルの反転にしてください。

グレーマップごとの入れ先

手元のグレーマップUnity HDRPマスクマップUnity URPチャンネルパックglTF 2.0 / Godot ORM
メタリックRRB
アンビエントオクルージョンGG(テクスチャをOcclusionにも割り当てると読まれる)R
ラフネスA、反転(スムースネス)A、反転(スムースネス)G
ディテールマスクB——
そのチャンネルに入れるマップがない定数0(例:ディテールなしのB)B = 0A = 255(未使用)

Nerulioの「Unity メタリック+スムースネス」プリセットは組み込みStandardシェーダーのページ(G・Bは未使用)に従い、Gに0を書きます。URPでオクルージョンも使うなら、手動割り当てでAOのファイルをGにしてください。

できること

  • プリセット:Unity HDRPマスク(M・AO・ディテール・スムースネス)、URPメタリック(M・–・–・スムースネス)、ORM(glTF 2.0・Godot 4)。
  • チャンネルごとの手動割り当て、定数0/255、チャンネル反転(ラフネス → スムースネス)。
  • CanvasではなくラボがPNGを直接書くので、アルファ0下のRGBを保持。
  • 各プリセットに順序の根拠となるドキュメントやエンジンのソースへのリンク。

使い方

  1. グレーマップをドロップ。
  2. プリセットを選ぶか、チャンネルを手動で割り当て。
  3. エンジンが逆を期待するチャンネルは反転。
  4. パックしたPNGをダウンロード。

出力されるファイル

ファイル用途
rock_metallic-mask.pngパックしたテクスチャ。最初に入れたファイルの名前になります。8ビットRGBAのPNGで、アルファ0の場所のRGBも保持します。
rock_metallic-mask-channels.zip任意の確認用:パックしたファイルをチャンネル分解で開き、4つの平面を保存して入力と比べます。

パックしたテクスチャをエンジンで使う

各エンジンのドキュメントにある手順で、Nerulioがこの読み込みを実行したわけではありません。

  1. Unity HDRP:PNGを読み込み、sRGB (Color Texture)をオフ、Texture TypeをDefaultにして、HDRP LitマテリアルのSurface InputsでMask Mapに割り当てます。マスクマップを割り当てるとMetallic・Smoothness・AOのRemappingスライダーが現れます。
  2. Unity URP:sRGB (Color Texture)をオフにして読み込み、LitマテリアルのWorkflow ModeをMetallicにし、テクスチャをMetallic MapとOcclusion Mapに割り当て、Smoothness › Sourceは既定のMetallic Alphaのままにします。
  3. Godot 4:ORMMaterial3Dを作り、ORMのPNGをORMテクスチャとして割り当てます。StandardMaterial3Dでも、ao_texture_channelをRed、roughness_texture_channelをGreen、metallic_texture_channelをBlueにすれば同じファイルを読めます。
  4. glTF 2.0:ORM画像をマテリアルのmetallicRoughnessテクスチャとして、オクルージョンを含むならオクルージョンテクスチャとしても参照します。ベースカラーは別のsRGB画像のままです。

結果の確認

  • パックしたPNGを同じ配置でチャンネル分解で開きます。各平面は入れたグレーマップと同じはずで(機能チェックでambientCGのグレーマップによりバイト一致を確認)、反転したチャンネルは255 − 値のはずです。
  • 定数チャンネルは、チャンネルの統計で最小 = 最大(0か255)と表示されます。
  • エンジンで、粗い部分はにぶく、磨いた部分は鋭く見えるはずです。逆ならスムースネスのチャンネルを反転していません。

トラブルシューティング

症状考えられる原因確認方法対処
Unityで粗い部分がつるつるに見えるラフネスを反転せずにアルファに入れたAを分解すると255 − ラフネスではなくラフネスそのものAの「反転」を付けてパックし直す
マップが違うチャンネルに入った入力は入れた順にチャンネルを埋めるプレビュー下の割り当ての行(例:R←1 · G←2 · B←3 · A←255)各チャンネルのプルダウンで正しいファイルを選ぶ
「All channel inputs must have the same dimensions」1枚だけサイズが違うファイル一覧に各サイズが出る先に全マップを同じサイズで書き出す
URPのマテリアルが環境光で暗くなるテクスチャをOcclusionにも割り当てたが、UnityプリセットがGに0を書いたGを分解すると最小 = 最大 = 0手動割り当てでAOのファイルをGにするか、Occlusion Mapを空にする
読み込み後、全体がてかりすぎ・つや消しすぎパックテクスチャをsRGBオンのまま読み込んだUnityのテクスチャのsRGB (Color Texture)sRGBをオフにする。値はデータ
チャンネルの値が想定と違う色のある入力が輝度にまとめられた入力がグレーでない(R・G・Bが異なる)色のある元画像を先に実際のチャンネルへ分解し、その平面をパックする

ほかの方法

方法こんなときに向いています
パックせずGodotのチャンネル選択を使うGodotのみ。StandardMaterial3Dは1枚のテクスチャの任意のチャンネルからマップを読むため、順番が違うだけの既存のパックファイルはパックし直す必要がありません。
テクスチャリングソフトの書き出しプリセットマップを描いたツールがエンジンの配置で直接書き出せるとき。GodotのドキュメントはORM用としてSubstance PainterとArmorPaint(Unreal Engineプリセット)を挙げています。
Shader Graph(Unity)どのプリセットにもない配置を使うとき。UnityのURPのページも、チャンネルを別の順でパックした場合はShader Graphを案内しています。

出力ファイルと検証方法

「測定確認」は、ダウンロードしたファイルをページ外(Pillow・numpy・独立したパーサー)で開き直して性質を測ったという意味です。ゲームエンジンでの読み込みは試していません。

書き出し先ファイル検証
Channel PNGs<name>-r/g/b/a.png (8-bit grey)測定確認 numpyチャンネルごとにバイト一致。完全に透明なテクセル下のRGBも保持。
Normal mapPNG · OpenGL (+Y) or DirectX (−Y)測定確認 numpyデコードしたベクトルは単位長(最大誤差0.0002)。OpenGLとDirectXは緑だけが異なります。
Packed mask / ORMUnity HDRP mask · URP metallic · ORM (glTF, Godot)測定確認 Pillowパック後のバイトを確認:ORMプリセット、AO 10 / ラフネス 80 / メタリック 220 → (10, 80, 220, 255)。
Engine importUnity · Unreal · Godot未検証どのエンジンでも読み込んでいません。

検証の根拠

チャンネル分解は4チャンネルすべてでバイト一致(最大差0)、透明テクセル2048個のRGBを保持。エッジブリードはアルファ0のテクセル448個だけを変更し、アルファは一切変更なし。OpenGL ↔ DirectXは緑(255 − g)だけが異なり、変換後の法線は単位ベクトル。

制限

  • チャンネルのバイトを正確に扱えるのはPNGだけです。JPEG・WebPはブラウザがデコードし「バイト一致ではない」と表示します。
  • インターレースPNGと16ビット出力は非対応。正確な経路は3,355万ピクセルまで。
  • ノーマルマップの規約はピクセルから判定できず、変換のみ可能です。
  • Unity・Unreal・Godotへの読み込みは行っていません。チャンネル順は各ドキュメントとエンジンのソースに基づきます。

バージョンと出典

テクスチャラボで測定(docs/TEXTURE-LAB.md):AO 10 / ラフネス 80 / メタリック 220にORMプリセットを使うと、ラボ内でもこのページでも(10, 80, 220, 255)。手動割り当ては(220, 10, 80, 0)、R反転は(245, 80, 220, 255)。ブラウザの機能チェックはambientCGのグレーマップ3枚をパックし、各チャンネルが入力とバイト一致することを確認します。配置は下記のドキュメント(GodotのORMの順序はエンジンのソース)に基づき、エンジンへの読み込みは実行していません。

参照した公式ドキュメント

よくある質問

UnrealのORM順は公式ですか?

EpicはR=AO・G=ラフネス・B=メタリックの順を文書化していません。ORMプリセットはglTF 2.0に従い、そのように表示します。

エンジンで読み込みましたか?

いいえ。パック後のバイトは確認しました(例:ORMプリセットで(10, 80, 220, 255))。Unity・Unreal・Godotへの読み込みは試していません。

無料ですか?アカウントは必要ですか?

このページの機能はすべて無料で、アカウントなしで使えます。透かしや制限された書き出しはありません。

スプライトはアップロードされますか?

いいえ。Studioはこのブラウザのタブ内でデコード・パック・書き出しを行います。プロジェクトはブラウザ(IndexedDB)に自動保存され、.nerulioファイルとして保存できます。

Asepriteやエンジンのプラグインは必要ですか?

いいえ。.asepriteファイルはブラウザで読み書きします。エンジン別のバンドルには必要なものが入っています(Godotはインポート設定とシーン、UnityとGodotのタイルセットは小さなエディタースクリプト)。