Unity 2D ノーマルマップ · セカンダリテクスチャ自動設定
Unity 2Dでノーマルマップが反映されないときは、たいてい次の4つのどれかが欠けています。2D Rendererを使うURP、ライトを受けるスプライトのマテリアル、_NormalMapという名前のセカンダリテクスチャ、法線マップを有効にしたLight2D。テクスチャ作業画面はノーマルマップを作り、テクスチャ側の設定を代わりに行うエディタースクリプトも書き出します。Unity 6ではGamma・Linearどちらのプロジェクトでも予測どおりのライティングになりました。

- Unity 6 URP 2D検証済み· Unity 6000.5.3f1 (URP 17.5)
- Godot 4 2D lights検証済み· Godot 4.7.2
- PNG set + JSON通常ファイル
できること
- Tools › Nerulio › Apply Texture JSONがスプライトの範囲を設定し、ノーマルマップをセカンダリテクスチャ_NormalMapとして追加。sRGBオフ、無圧縮、ミップマップなし、2の累乗へのリサイズなし。
- Tools › Nerulio › Create Lit PreviewがスプライトとStudioのライトごとのポイントLight2Dを作成。Normal Mapの品質はAccurate、Normal Map Distance=z÷Pixels Per Unit。
- Pixels Per Unitはnerulio-texture.json内の数値(既定100)。ライトの位置・半径・距離はこの値で割られます。
- UnityのREADMEはドット絵向けにLight Render Texture Scaleを案内。新しい2D Rendererでは0.5で、ライティングの解像度が半分になります。
- Unity 6000.5.3f1、URP 17.5、2D Rendererで12/12合格(実在素材6件×Gamma・Linear)、平均誤差0.0037〜0.0085。
- ノーマルマップはUnityが読むOpenGL形式(Y+)。ほかのツールで作ったDirectX形式は、使う前にチェックパネルで判定できます。
使い方
- スプライトかシートをドロップ(シートは先にスプライト作業画面で切り分け)。
- ベベルを調整してライトを置き、Cキーで平面とライティングを並べて比較。
- 書き出し(Ctrl+E)でUnity 6 URP 2Dにチェック。
- unityフォルダーをAssets/にコピーし、エディタースクリプトのコンパイルを待つ。
- Tools › Nerulio › Apply Texture JSONを実行し、続けてCreate Lit Preview。
Unity 2Dノーマルマップの設定
| 設定 | インポーターが入れる値 | 合っていないと起きること |
|---|---|---|
| セカンダリテクスチャ名 | アルベドのスプライトに_NormalMap | 別の名前だとライト用スプライトシェーダーが読まない |
| sRGB (Color Texture) | オフ(色ではなくベクトル) | ガンマ変換がかかり、凹凸の向きが狂う |
| Non-Power of 2 | None | 96×64が128×64に伸びて法線がぼやけた(平均誤差0.005ではなく0.045) |
| 圧縮・ミップマップ | 無圧縮、ミップマップなし | 圧縮や平均化されたテクセルは書き出したベクトルと変わる |
| Max Size | シートに合わせて引き上げ(2048〜16384) | 既定の2048では大きなシートが縮む |
| Light2Dの法線マップ | 品質Accurate、Distance=z÷Pixels Per Unit | 法線マップが無効だと無視され、距離が違うと凹凸が平らすぎる・強すぎる |
| Light Render Texture Scale | 変更しない(プロジェクト設定)。READMEで1を推奨 | 0.5だと小さなスプライトのライティングがカクカクに |
表はUnity 6000.5.3f1とURP 17.5で、同梱のインポーターが行った内容です。ほかのUnity・URPのバージョンは試していません。
エンジン別の書き出しと検証方法
「検証済み」は、実際のCC0アセットから書き出したファイルを本物のエンジン・ツールで読み込み、元データと比較したという意味です。読み込んでいない形式はそのように表示します。
| 書き出し先 | ファイル | 検証 |
|---|---|---|
| Godot 4 2D lights | _lit.tscn · CanvasTexture .tres · normal / specular PNG | 検証済み Godot 4.7.2実在のCC0ケース6件をGodot(gl_compatibility)で描画し、確認した全フレームがStudioのライティングプレビューと1/255以内で一致。緑を反転した同じ描画は3.8〜37段階ずれるため、規約の誤りを検出できます。 |
| Unity 6 URP 2D | PNG · nerulio-texture.json · Editor/NerulioNormalMapImporter.cs | 検証済み Unity 6000.5.3f1 (URP 17.5)12回中12回合格(6ケース×ガンマ・リニア色空間):URPが適用したライティングが書き出したノーマルマップと一致(平均誤差0.0037〜0.0085)。光の減衰はURP独自なので、明るさはプレビューではなくUnityの基準です。 |
| PNG set + JSON | albedo · _n (OpenGL) · _n_dx (DirectX) · 16-bit height · AO · specular · manifest | 通常ファイルどのエンジン・ツールでも使える通常ファイルで、エンジンでの実行検証はうたっていません。 |
検証の根拠
Godot 4.7.2で実在のCC0ケース6件(ドット絵、HDスプライト、繰り返しテクスチャ、読み込んだDirectXマップ)を描画し、確認した全フレームがStudioのプレビューと1/255以内。Unity 6000.5 URP 2D:12回中12回合格(6ケース×ガンマ・リニア)。規約が分かっている実在のマップでOpenGL/DirectX判定:1Kのマップ128枚で100%正解、1,562サンプル中で誤った「高」判定は0件(「緑が明るければOpenGL」という単純な規則は46%)。
制限
- 透明な縁がない絵(繰り返しテクスチャ)では、赤の反転とDirectXの緑を区別できません。チェックパネルがそれを伝え、「赤を反転」を用意しています。
- シートはスプライト作業画面でフレームを切るまで1枚の絵としてライティングされます。テクスチャ作業画面ではフレームを切りません。
- リムライトはプレビュー専用で、Unityにはスペキュラーマップを書き出しません(Godotには書き出し)。
- Unityは独自の光の減衰を使います。書き出したノーマルマップはUnityで検証済みですが、明るさの曲線はUnityのものです。
よくある質問
Unity 2Dでノーマルマップが反映されないのはなぜ?
順に確認してください。プロジェクトが2D Rendererを使うURPか、スプライトのマテリアルがSprite-Lit-Defaultか、ノーマルマップが正確に_NormalMapという名前のセカンダリテクスチャか、Light2Dで法線マップが有効か。テクスチャ側はインポーターが担当し、パイプライン・マテリアル・自分で置いたライトはご自身で設定します。
ドット絵のライティングがぼやけてカクカクします
2D Rendererは既定で2Dライティングを半分の解像度で計算します(Light Render Texture Scale 0.5)。2D Rendererのアセットで1にしてください。プロジェクト設定なので書き出しでは変更せず、検証では1にしていました。
Unity 6で修正前は何が起きていましたか?
検証で見つかった自社インポーターのバグ3件です。Unity 6でLight2DがUnity.RenderPipelines.Universal.2D.Runtimeアセンブリに移り、プレビューにライトが作られなかった。URP 17ではNormal Map Distance・Qualityが読み取り専用のため、今はSerializedObject経由で設定。96×64のマップが128×64にリサイズされてぼやけた(平均誤差0.045→リサイズNoneで0.005)。
明るさもStudioと同じですか?
いいえ。位置・色・高さ・強さはStudioの値ですが、減衰はURP独自の曲線なので、明るさのカーブはUnityのものです。検証で比べたのは法線の項(N·L)で、全体の明るさではありません。Unityにはスペキュラーマップも渡りません。
無料ですか?アカウントは必要ですか?
このページの機能はすべて無料で、アカウントなしで使えます。透かしや制限された書き出しはありません。
スプライトはアップロードされますか?
いいえ。Studioはこのブラウザのタブ内でデコード・パック・書き出しを行います。プロジェクトはブラウザ(IndexedDB)に自動保存され、.nerulioファイルとして保存できます。
Asepriteやエンジンのプラグインは必要ですか?
いいえ。.asepriteファイルはブラウザで読み書きします。エンジン別のバンドルには必要なものが入っています(Godotはインポート設定とシーン、UnityとGodotのタイルセットは小さなエディタースクリプト)。