本文へスキップ

テクスチャのチャンネル分解 · RGBA・ORMをグレーマップに

ブラウザのCanvasで読んだパック済みテクスチャは、アルファ0の下のバイトをすべて失います。テクスチャラボはPNGを直接デコードするので、各チャンネルが保存されたとおりに出てきます。

チャンネルパックテクスチャは、互いに無関係なグレーマップを最大4枚、R・G・B・Aの各チャンネルに入れたものです。ORMテクスチャはR・G・Bにオクルージョン・ラフネス・メタリックを、Unity HDRPのマスクマップはメタリック・AO・ディテールマスク・スムースネスを持ちます。分解するとは、各チャンネルを1バイトも変えずに単一チャンネルの画像に書き出すことです。チャンネル分解はPNGを直接読み、選んだ配置(HDRP・URP・glTF・Godot ORM・Unreal ORM)に従って各チャンネルに意味を付け、チャンネルの反転(スムースネス ↔ ラフネス)もでき、完全に透明なテクセルの下まで元とバイト一致の8ビットグレーPNGとして保存します。

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

パックテクスチャの中身と、順番が大事な理由

パックテクスチャの各チャンネルはテクセルごとの独立した0〜255の数値で、色の一部ではありません。絵として見ると不思議な色に見え、Gがラフネス(glTF・Godot ORM)なのか、アンビエントオクルージョン(Unity HDRP)なのか、オクルージョン(Unity URP)なのかは配置を知らないと分かりません。ファイル名から順番はまず分かりません。_ORM・_ARM・_MaskMap・_packedはどれも「パック済み」を意味するだけなので、ラボはすべてパックマップに分類し、配置は自分で選ぶ形にしています。

データが失われるのはアルファチャンネルです。Unityのマスクマップでは、完全に粗いテクセルはスムースネス0、つまりアルファ0です。ブラウザのCanvasはピクセルを乗算済みで保持するため、そのテクセルのメタリック・AO・ディテールのバイトは0として返ります。チャンネル分解は自前のリーダーでPNGをデコードし(インターレース以外の全カラー形式、1〜16ビット、tRNS)、各チャンネルを色変換なしの1テクセル1バイト、カラー形式0のPNGとして書き出します。

反転は厳密です。保存される値は255 − 値で、2回反転すると元のバイトに戻ります。Unityのスムースネスのチャンネルは、こうして他のエンジンが求めるラフネスになります。

チャンネル平面
1チャンネル分のw × hバイト。グレーのPNGとして保存します。
乗算済みアルファ
アルファを掛けた後の色。アルファ0では色がすべて0になり、そこにパックされたバイトは失われます。
マスクマップ
Unity HDRPのパックテクスチャ。Rメタリック・Gアンビエントオクルージョン・Bディテールマスク・Aスムースネス。
16ビット入力
受け付けますが、サンプルごとに上位バイトを使います。出力は常に8ビットです。

例:HDRPマスクマップの1テクセル

AOが200でディテールマスクのない、完全に粗い金属のテクセルです。スムースネスが0なのでアルファも0です。

元のテクセル (crate_MaskMap.png)   R 255   G 200   B 0   A 0
ブラウザのCanvasで読む             R 0     G 0     B 0   A 0     (乗算済み:色 × 0)
ラボのPNGデコーダーで読む          R 255   G 200   B 0   A 0

Unity HDRPの配置で保存、Aを反転:
  crate_MaskMap-r-metallic.png                 255
  crate_MaskMap-g-ao.png                       200
  crate_MaskMap-b-detail.png                   0
  crate_MaskMap-a-inverted-smoothness.png      255   (255 − 0:ラフネス)

反転したファイルは配置上の名前(smoothness)の前にinverted-が付くので、中身はラフネスです。ほかのツールがファイル名でマップを選ぶ場合は名前を変えてください。

配置ごとの各チャンネルの中身

チャンネルUnity HDRPマスクマップglTF 2.0 / Godot ORMUnity URPチャンネルパック
Rメタリックオクルージョンメタリック
Gアンビエントオクルージョンラフネスオクルージョン
Bディテールマスク(HDRPのみ)メタリック未使用
Aスムースネス — 反転でラフネス未使用スムースネス — 反転でラフネス

組み込みのStandardシェーダーのメタリックマップはR(メタリック)とA(スムースネス)だけを読みます。Nerulioの「Unity URP・組み込み」プリセットはこのページに従ってGを「無視」と表示しますが、UnityのURPのページは、同じテクスチャをOcclusionにも割り当てるとGからオクルージョンを読むとしています。

できること

  • チャンネル(R・G・B・A)ごとに8ビットのグレーPNGを1枚、元とバイト一致。
  • 完全に透明なテクセル下のRGBを保持(2048テクセルで確認)。
  • 選んだエンジン配置(Unity HDRP・URP・ORM)での意味つきでチャンネルをプレビュー。
  • チャンネルの反転(例:ラフネス ↔ スムースネス)と保存。

使い方

  1. パック済みPNGをドロップ。
  2. エンジン配置を選び、各チャンネルの意味を確認。
  3. 必要ならチャンネルを反転。
  4. チャンネルPNGをダウンロード。

出力されるファイル

ファイル用途
crate_MaskMap-r-metallic.png … -a-smoothness.pngチャンネルごとに8ビットのグレーPNG(カラー形式0)を1枚。名前はファイル-チャンネル-役割で、反転した場合は役割の前にinverted-が付きます。
crate_MaskMap-channels.zip4チャンネルのPNGを1つのアーカイブに(4チャンネルすべて保存)。

パックテクスチャを別のエンジンの配置へ移す

例:Unity HDRPのマスクマップをGodot 4やglTFへ移す場合。エンジンの設定は各ドキュメントに従ったもので、Nerulioは読み込みを実行していません。

  1. パック済みのPNGを開き、「チャンネルの解釈」を元の配置(ここではUnity HDRPマスクマップ)にします。チャンネルの統計を見てください。最小 = 最大のチャンネルは定数で埋められたものです。
  2. Aの「反転」を押してスムースネスをラフネスにし、「4チャンネルすべて保存(ZIP)」を押します。
  3. Godot 4で個別マップとして使う:StandardMaterial3Dのテクスチャスロットにラフネス・メタリック・AOのPNGを割り当てます(Ambient Occlusionは先に有効化)。各スロットの*_texture_channelの既定はRedなので、グレーPNGはそのまま読まれます。
  4. GodotのORMMaterial3DやglTF:マスクパッカーのORMプリセット(Rオクルージョン・Gラフネス・Bメタリック)でAO・ラフネス・メタリックをパックし直します。
  5. Unity:グレーPNGやパックし直したテクスチャはすべてsRGB (Color Texture)をオフにして読み込みます。URP・HDRPにはラフネス専用のスロットがないため、平面を1枚ずつ使わず、メタリックとスムースネスをパックし直してください。

結果の確認

  • 分解したときと同じ配置で平面をパックし直し、それを分解します。各チャンネルの最小・最大・平均・固有値の数が前と同じはずです(ラボの測定:最大差0)。
  • 保存したPNGを任意の画像ツールで開きます。RGBのコピーではなく、元の解像度の単一チャンネル8ビットグレー画像のはずです。
  • 反転した平面では、以前vだったテクセルが255 − vになっているはずです(ステージに元 → 結果が並んで表示されます)。

トラブルシューティング

症状考えられる原因確認方法対処
別のツールで、透明な場所ごとにチャンネルが黒くなるそのツールが乗算済みアルファでファイルを読んだ同じPNGをチャンネルステージで開くとバイトは残っているラボで分解し、パックデータはCanvasを使うツールに通さない
ファイルに「ブラウザでデコード(バイト一致ではない)」と出るJPEG・WebPの入力。JPEGの圧縮はチャンネル同士を混ぜることもあるファイル一覧とレポートのexactChannels: falseテクスチャの元になったPNGを分解する
分解した「AO」がラフネスに見える、メタリックが荒れている配置の選択が違う(GはHDRPではAO、glTFではラフネス)「チャンネルの解釈」を切り替えて統計とプレビューを比べるテクスチャを書き出したソフトの配置を選ぶ
移した先のエンジンでラフネスが逆に見える元のチャンネルがスムースネス(Unity)で、反転していないファイル名にinverted-がないそのチャンネルの「反転」を押して保存し直す
16ビットのテクスチャの精度が落ちる出力は8ビットで、サンプルごとに上位バイトだけを残すレポートのビット深度16ビットの平面が必要なら16ビット対応の編集ソフトを使う

ほかの方法

方法こんなときに向いています
パックしたまま使うGodotのStandardMaterial3Dはマップごとに読むチャンネルを選べる(roughness_texture_channel・metallic_texture_channel・ao_texture_channel)ため、順番が違うだけなら分解は不要です。
画像編集ソフトのチャンネル分解アルファ0のテクセルがない不透明なテクスチャを、すでにそのソフトで扱っているとき。マスクマップなら透明な部分を先に確認してください。
ラフネスをスムースネスにUnity向けに反転したグレーマップが1枚だけ必要なとき。

出力ファイルと検証方法

「測定確認」は、ダウンロードしたファイルをページ外(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):ランダムなバイトの64×64 ORMを分解するとR・G・B・Aすべて最大差0、アルファ0のテクセル2048個がすべてRGBを保持(わざと入れた(1, 2, 3, 0)の角はR = 1で復元)、ファイルはPillowでモードL・64×64として開け、反転したラフネスの平面は正確に255 − ラフネス。配置は下記のエンジンのドキュメントのもので(GodotのORMの順序はエンジンのソース)、エンジンへの読み込みは行っていません。

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

よくある質問

画像編集ソフトで開くのではだめ?

多くの編集ソフトとすべてのブラウザCanvasはアルファを乗算するため、透明テクセル下のメタリック・ラフネスのバイトが0になります。この経路はPNGのバイトを直接読みます。

JPEGでも使えますか?

使えます。ただしJPEGはブラウザがデコードし、「バイト一致ではない」と表示します。

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

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

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

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

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

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