ラフネスをスムースネスに変換 · Unity向けチャンネル反転
Unityのメタリックワークフローはスムースネスを読みますが、多くのテクスチャツールはラフネスを書き出します。反転は単純な計算ですが、バイトが残ることが前提です。テクスチャラボはPNGを直接読むので、保存される値は正確に255 − ラフネスです。
Unityのメタリックワークフローはスムースネスを読みますが、glTF・Godotや多くのPBRテクスチャの素材はラフネスを提供します。Unityのシェーダーライブラリは知覚ラフネスを1 − スムースネスと定義しているので、変換は厳密な反転です。スムースネス = 1 − ラフネス、8ビットのPNGでは255 − 値です(ラフネス80 → スムースネス175)。リニアなデータのまま反転し、結果をUnityが読む場所、つまりURP・組み込みのメタリックマップのアルファか、HDRPのマスクマップのアルファに入れます。Nerulioはブラウザ上でチャンネルをバイト単位で正確に反転し(測定済み)、Unityへの読み込みは実行していません。

- Channel PNGs測定確認· numpy
- Normal map測定確認· numpy
- Packed mask / ORM測定確認· Pillow
- Engine import未検証
ラフネス・スムースネスと、ガンマが問題になる理由
2つのマップは同じ性質を逆側から表します。ラフネス0が鏡、1が完全に粗い面で、スムースネスは1が鏡です。UnityのレンダーパイプラインのシェーダーライブラリではPerceptualSmoothnessToPerceptualRoughnessが1 − スムースネスを返し、その後で値を2乗します(PerceptualRoughnessToRoughness)。どちらのマップもアーティストが描く知覚値を保存しているので、反転するだけで、2乗や平方根はとりません。
反転が厳密なのはリニアなデータのときだけです。ラフネスマップのバイトは色ではなく数値です。カラーマネジメントをする編集ソフトやsRGBをオンにしたインポーターなど、どこかでsRGBとして扱われると値がずれます。スムースネスのバイト175はリニアなら0.686ですが、sRGBとしてデコードすると約0.429です。結果はsRGB (Color Texture)をオフにして読み込み、ガンマカーブで「補正」しないでください。
スムースネスの入れ先。URPのLitはMetallic Mapのアルファ(Smoothness › Source Metallic Alpha、既定)かベースマップのアルファから読みます。URPのチャンネルパックテクスチャと組み込みStandardシェーダーのメタリックマップはAに、HDRPのマスクマップもAに持ちます。グレーのスムースネスPNG単体は、カスタムシェーダーかパック用にしか使えません。
グロス(glossiness)マップはすでにスムースネスです。そのためNerulioの名前のルールはglossをスムースネスに分類し、反転するとラフネスに戻ってしまいます。
- ラフネス
- 0 = 鏡のように滑らか、1(255)= 完全に粗い。glTF・Godot・Unrealの規約。
- スムースネス
- Unityの逆値:1 − ラフネス。
- 知覚ラフネス
- 描いて保存する値。エンジンはライティングの前に2乗します。
- リニア(非カラー)データ
- sRGBデコードせず保存値のまま使う値。
例:数値で見る
ラフネスのバイト4つを、ラボが書くとおりに反転した値です。
ラフネスのバイト ラフネス スムースネス = 1 − r スムースネスのバイト (255 − v)
0 0.000 1.000 255
80 0.314 0.686 175
128 0.502 0.498 127
255 1.000 0.000 0
同じバイト175をsRGB (Color Texture)オンで読み込むと:
175 / 255 = 0.686 → sRGBデコード → 0.429 (目に見えて粗い面)2回反転すると元のバイトに戻るので、変換で何も失いません。ラボはダウンロードしたファイルで、保存した平面がすべてのテクセルで255 − ラフネスと一致することを測定しました。
ラフネスからUnityのスムースネスへ
| 手元にあるもの | Nerulioで | Unityで |
|---|---|---|
| グレーのラフネスPNG | チャンネル:ラフネスと表示されたチャンネルを反転して保存 | グレーのスムースネスマップ(パックやカスタムシェーダー用) |
| ラフネス + メタリックのPNG | マスクパッカー、「Unity メタリック+スムースネス」プリセット:R ← メタリック、A ← ラフネス反転 | URP・組み込み:Metallic Map、スムースネスはMetallic Alphaから |
| ラフネス + メタリック + AO(+ ディテール) | マスクパッカー、「Unity HDRP マスク」プリセット:Rメタリック、G AO、Bディテールか0、Aラフネス反転 | HDRP Lit:Mask Map |
| ORMテクスチャ(Gにラフネス) | チャンネル、ORM配置:Gを反転して保存し、Aにパック | メタリックマップかマスクマップのアルファ |
| グロス・glossinessマップ | 反転不要:すでにスムースネス | そのままAにパック |
できること
- 正確に255 − vを書くチャンネル反転(ダウンロードしたファイルをnumpyで確認)。
- ブラウザのCanvasなら失う、完全に透明なテクセル下のバイトを保持。
- Unity HDRP(マスクマップ)やURP(アルファにメタリック+スムースネス)での意味つきのチャンネルプレビュー。
- パッカーへ続けて:スムースネスはURPメタリックマップかHDRPマスクマップのアルファに入ります。
使い方
- ラフネスマップ(PNG)をドロップ。
- チャンネルを反転。
- スムースネスマップを保存するか、マスクパッカーを開く。
- Unityプリセットでメタリック(HDRPならAOも)と一緒にパック。
出力されるファイル
| ファイル | 用途 |
|---|---|
rock_roughness-g-inverted-roughness.png | 反転した平面の8ビットグレーPNG。名前は元の役割(roughness)の前にinverted-が付くので、中身はスムースネスです。 |
rock_metallic-mask.png | マスクパッカーの結果:Rにメタリック、Aに反転したラフネス(HDRPならAOとディテールも)。Unityのマテリアルにそのまま使えます。 |
Unityが読む場所にスムースネスを入れる
Unityの手順はUnity 6・HDRP 17.1のドキュメントに従ったもので、Nerulioは読み込みを実行していません。
- マスクパッカーを開き、メタリックマップを1枚目、ラフネスマップを2枚目に入れて、「Unity メタリック+スムースネス」(URP・組み込み)か「Unity HDRP マスク」を選びます(HDRPでディテールマスクがなければAOをGに、Bは0に)。
- Aチャンネルの「反転」を付け、パックしたPNGをダウンロードします。URPでアンビエントオクルージョンも使うなら手動割り当てに切り替え、AOのファイルをGにします。
- Unityでテクスチャを選び、
sRGB (Color Texture)をオフにします。HDRPではTexture TypeもDefaultにします。 - URP Lit:Workflow Mode
Metallic、テクスチャをMetallic Map(GにAOがあればOcclusion Mapにも)に割り当て、Smoothness › SourceはMetallic Alphaのままにします。 - HDRP Lit:Surface InputsのMask Mapに割り当てます。調整が必要ならSmoothness Remappingのスライダーで範囲を合わせ直します。
結果の確認
- パックしたPNGをチャンネル分解で開きます。Aはどこでも255 − ラフネスのはずです(ラフネス80のテクセルは175)。
- Unityで粗い部分(にぶく広いハイライト)と磨いた部分(鋭いハイライト)を比べます。逆なら反転していないか、2回反転しています。
- テクスチャのインスペクターで、パックマップの
sRGB (Color Texture)がオフになっているはずです。
トラブルシューティング
| 症状 | 考えられる原因 | 確認方法 | 対処 |
|---|---|---|---|
| 全体が濡れたよう、鏡のように見える | ラフネスを反転せずアルファに入れた | Aを分解してラフネスマップと比べると、反転されず同じ | Aの「反転」を付けてパックし直す |
| テクスチャリングソフトより面が粗く見える | パックマップをsRGBで読み込んだ(175が約0.429になる) | UnityのインスペクターでsRGB (Color Texture)がオン | オフにする。ガンマカーブで補正しない |
| スムースネスマップが効かない | Smoothness › SourceがAlbedo Alpha、またはどこかのツールがアルファなしでPNGを保存した | マテリアルのインスペクターを確認し、PNGを分解してAが定数255でないか見る | SourceをMetallic Alphaにし、パックマップはRGBAのPNGで保存 |
| つやのあった部分が粗くなったグロスマップ | グロスマップはすでにスムースネスなのに反転した | 元のファイル名にglossやglossinessがある | 反転せずにパックする |
| URPのマテリアルが環境光で暗くなる | パックテクスチャをOcclusionにも割り当てたが、Gが0で書かれている | Gを分解すると定数0 | 手動割り当てでAOのファイルをGにするか、Occlusion Mapを空にする |
ほかの方法
| 方法 | こんなときに向いています |
|---|---|
| 画像編集ソフトで反転 | カラーマネジメントをしないソフトで8ビットのグレーのラフネスマップを扱うとき。反転結果は同じ255 − vですが、アルファへのパックは自分で行う必要があります。 |
| Shader Graph(Unity) | ラフネスのテクスチャのまま、シェーダー内で反転したいとき。UnityのURPのページは、既定と違うパックにはShader Graphを案内しています。 |
| チャンネル分解 | ラフネスが別のパックテクスチャ(ORMのG)の中にあり、先に取り出す必要があるとき。 |
出力ファイルと検証方法
「測定確認」は、ダウンロードしたファイルをページ外(Pillow・numpy・独立したパーサー)で開き直して性質を測ったという意味です。ゲームエンジンでの読み込みは試していません。
| 書き出し先 | ファイル | 検証 |
|---|---|---|
| Channel PNGs | <name>-r/g/b/a.png (8-bit grey) | 測定確認 numpyチャンネルごとにバイト一致。完全に透明なテクセル下のRGBも保持。 |
| Normal map | PNG · OpenGL (+Y) or DirectX (−Y) | 測定確認 numpyデコードしたベクトルは単位長(最大誤差0.0002)。OpenGLとDirectXは緑だけが異なります。 |
| Packed mask / ORM | Unity HDRP mask · URP metallic · ORM (glTF, Godot) | 測定確認 Pillowパック後のバイトを確認:ORMプリセット、AO 10 / ラフネス 80 / メタリック 220 → (10, 80, 220, 255)。 |
| Engine import | Unity · 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):ラフネスマップのGを反転してダウンロードすると、平面は正確に255 − ラフネスで、ステージには元 → 結果が並んで表示されました。パッカーのR反転のチェックはAO 10から(245, 80, 220, 255)を出しました。1 − スムースネスの関係はUnityのレンダーパイプラインのソース、チャンネルの位置とインポート設定は下記のUnityのページに基づきます。Unityへの読み込みは実行していません。
参照した公式ドキュメント
よくある質問
Unityはスムースネスをどのチャンネルから読みますか?
URPメタリックはメタリックマップのアルファ、HDRPマスクマップもアルファです(Rメタリック・G AO・Bディテールマスク)。どちらの順序もUnityのドキュメントに基づき、ラボで引用しています。
Unityで読み込みましたか?
いいえ。バイトは確認しましたが、ここではUnityへの読み込みは行っていません。
無料ですか?アカウントは必要ですか?
このページの機能はすべて無料で、アカウントなしで使えます。透かしや制限された書き出しはありません。
スプライトはアップロードされますか?
いいえ。Studioはこのブラウザのタブ内でデコード・パック・書き出しを行います。プロジェクトはブラウザ(IndexedDB)に自動保存され、.nerulioファイルとして保存できます。
Asepriteやエンジンのプラグインは必要ですか?
いいえ。.asepriteファイルはブラウザで読み書きします。エンジン別のバンドルには必要なものが入っています(Godotはインポート設定とシーン、UnityとGodotのタイルセットは小さなエディタースクリプト)。