本文へスキップ

ノーマルマップはOpenGLかDirectXか · 判定と変換

出っ張りがへこんで見える、光が逆から当たって見えるときは、ノーマルマップの緑(G)チャンネルの規約がエンジンと逆なことがほとんどです。GodotとUnityはOpenGL形式(Y+)、UnrealはDirectX形式(Y−)を読みます。ファイル名や目視の判断は意外とよく外れます。

OpenGLとDirectXのノーマルマップの違いは緑チャンネルだけです。OpenGL方式の緑(Y+)は「上向き」でGodotとUnityが読み、DirectX方式(Y−)は「下向き」です。規約を間違えたマップは上下の縁の陰影が入れ替わり、上から照らすと凸が半分凹に見える一方、左右は正しく見えます。緑を反転する(255 − g、劣化なし)か、エンジンのインポート時の反転を使ってください。どちらか分からないときはStudioのチェックパネルが測定し、確定するまで何も変えません。

スプライト、スプライトシート、繰り返しテクスチャ(PNG)をドロップ
空のStudioを開く
ブラウザ内で処理し、ファイルはアップロードされません。
Studio のテクスチャ作業画面:読み込んだambientCGのノーマルマップを高い信頼度でDirectXと判定。規約を確定するまで何も変わらない画面
CC0アセット(ambientCG)を開いた実際のStudio画面です。
書き出し先
  • Godot 4 2D lights検証済み· Godot 4.7.2
  • Unity 6 URP 2D検証済み· Unity 6000.5.3f1 (URP 17.5)
  • PNG set + JSON通常ファイル

緑チャンネルの意味と、反転を見落としやすい理由

接空間ノーマルマップでは、赤がX(画像の右)、青がZ(面の外側)、緑がYです。2つの規約は赤と青では一致し、Yがどちらを向くかだけが違います。GodotのCanvasTextureのリファレンスはGodotがX+、Y+、Z+の座標を期待するとし、UnityのマニュアルはUnityがY+のノーマルマップ(「OpenGL形式とも呼ばれる」)を使うとしています。

PNGにはどちらの規約かが書かれておらず、どちらも正しいマップです。左右のライティングは正しいままなので、反転は見落としやすいものです。入れ替わるのは陰影の上下半分だけなので、ライトを左右に動かしても問題なく、上下に動かすとおかしくなります。配布元がファイル名で示していれば(ambientCGのNormalGL・NormalDX)手がかりになりますが、そうでなければ推測にすぎません。

Nerulioのチェックパネルはこれを測定します。OpenGLとして読むと、実在する面の傾きは互いに矛盾しないはずで(高さ場の交差微分が等しい)、DirectXのマップは逆の符号でそれを崩します。スプライトでは、シルエットの法線が外を向いているかを見る2つ目の検査も行います。判定にはそれぞれ信頼度と根拠が付き、斜めの凹凸がないマップには推測ではなく「判定できない」が出ます。

赤の反転が問題の残り半分です。Xを逆に書く生成ツールがあり、比較測定ではNormalMap-Onlineの既定の出力がそうでした。スプライトならシルエットの検査が赤を単独で測り「赤が反転」と報告しますが、不透明なテクスチャでは赤の反転と緑の反転はどんな検査でも同じに見え、パネルもそう表示します。

Y+(OpenGL)
緑が128より大きい=画像の上を向く。Godot、Unity。
Y−(DirectX)
緑が128より大きい=下を向く。例:ambientCGのNormalDXファイル。
緑の反転
g → 255 − g。2回行うと元のバイトに戻ります。

具体例:上を向いたピクセル1つを2通りに読む

Nerulioが写したGodotの2Dライトのモデルで計算。白いピクセル1つと点光源1つ、環境光なし:

画像の上へ45°傾いた面
  OpenGLのバイト (128, 218, 218)      DirectXのバイト (128, 37, 218)

ライトがピクセルの上64px、高さ64px:
  OpenGLのマップをOpenGLとして読む    N·L = 1.00  → 255(最も明るい)
  DirectXのマップをOpenGLとして読む   N·L = 0.00  →   0(暗い)
同じライトをピクセルの下64pxに置くと:
  DirectXのマップをOpenGLとして読む   N·L = 1.00  → 255:逆側から照らされる

反転:255 − 37 = 218、255 − 218 = 37   (2回で元のバイト)

横向きの面は反転しても変わらないので、マップが間違っていても左右のライトの試験は通ってしまいます。必ずライトを上か下に置いて試してください。

できること

  • チェックパネルは表面そのものから規約を測ります。OpenGLとして読んだとき実在の表面なら傾きどうしが矛盾せず、DirectXのマップはそれを測れる形で崩します。
  • スプライトではシルエットによる独立した2つ目の検査も。縁の法線は外を向くはずで、2つの検査が一致すると信頼度が上がります。
  • 判定には信頼度と根拠を表示。斜めの起伏がない平らなマップは推測せず判定なしに。「OpenGL です/DirectX です」を押すまで何も変わりません。
  • スプライトでは反転した赤(R)チャンネルも検出し、Flip red(X−)で修正。透明な縁のないテクスチャでは赤と緑を区別できず、パネルがそう伝えます。
  • 両方の規約で書き出し。PNGセットに_n(OpenGL)と_n_dx(DirectX)、または片方だけの法線マップPNG 1枚。

使い方

  1. テクスチャ作業画面に画像とそのノーマルマップを入れる。
  2. 法線マップパネルでソースを読み込んだノーマルマップにする。
  3. チェックパネルで判定、信頼度、根拠を読む。
  4. 「OpenGL です」か「DirectX です」を押し(指摘があればFlip redも)、Cでフラットとライティングを比較。
  5. エンジンが読む規約で、または両方入りのPNGセットで書き出す。

結果の確認

  • ライトの試験:真上のライトは上を向いた縁を、真左のライトは左を向いた縁を明るくするはずです。
  • 形の分かっているものでバイトを確認:ドームや面取りしたボタンの上半分は、OpenGLのマップなら緑が128より大きくなります。
  • 往復の試験:緑を2回反転して元のファイルと比べると、バイトが完全に一致するはずです。

エンジンごとに使うノーマルマップ

エンジン・入手元緑の規約Studioから使うファイル
Godot 4OpenGL(Y+)_n.png、またはGodot 4バンドル(CanvasTextureとライト付きシーン)
Unity(URP 2D)OpenGL(Y+)_n.png、またはUnity 6バンドル(Secondary Texture _NormalMap)
Unreal EngineDirectX(Y−)_n_dx.png
ambientCGのダウンロードNormalGL = OpenGL、NormalDX = DirectXGodotとUnityにはNormalGL
出どころ不明のマップチェックパネルで測定判定を確定してからどちらかを書き出し
赤が逆のスプライト用マップ赤反転(X−)Flip red(X−)の後で書き出し

トラブルシューティング

症状考えられる原因確認方法対処
ライトが上なのに下から照らされたようで、左右は正しいエンジンが読むのと別の緑の規約真上にライトを置くと上の縁が明るくなるか緑を反転。GodotならImportドックでProcess › Normal Map Invert Yをオンにして再インポート
ライトが左なのに右が明るく、上下は正しい生成ツールが赤を反転して保存した片側から照らす。スプライトならチェックパネルが「赤が反転」と表示チェックパネルの赤を反転(X−)、またはそのツールの赤の反転をオフにして作り直す
どの方向からも逆:凸が凹高さそのものが反転している(赤と緑の両方が反転)上の2つの試験が同時に失敗反転した高さから作り直すか、赤と緑を一緒に反転
パネルが「判定できない」と出す斜めの凹凸がない。まっすぐな溝、単一の坂、平面には向きの情報がないマップに丸い形や斜めの形があるか配布元で判断する(ambientCG・Poly Havenはファイル名に表記)か、照らして見る
手描きのドット絵スプライトで信頼度が低い様式化したマップでは2つの検査の答えが食い違う判定の下の根拠の行上から照らして目で確かめる。「OpenGL です」か「DirectX です」を押すまで適用されない
緑を反転してもUnityでおかしいsRGB(Color Texture)がオンで、マップがガンマ変換されているノーマルマップのインポート設定sRGBをオフに。Unity 2Dのノーマルマップを参照

ほかの方法

方法こんなときに向いています
OpenGL ↔ DirectX変換(テクスチャラボ)規約がすでに分かっていて、ファイル全体の緑を一度に反転すればよいとき。
エンジンのインポート時の反転GodotのProcess › Normal Map Invert Yはファイルをそのままにして読み込み時に反転します。同じファイルをDirectX方式のエンジンと共有するときに便利です。

エンジン別の書き出しと検証方法

「検証済み」は、実際の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 2DPNG · 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 + JSONalbedo · _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の判定の横にそう表示します。
  • 判定は信頼度付きの測定で保証ではなく、確定するまで何も適用しません。
  • 高さの推定を誤って作ったマップのように、形そのものが間違っているマップはNerulioでは直せません。
  • 透明な縁がない絵(繰り返しテクスチャ)では、赤の反転とDirectXの緑を区別できません。チェックパネルがそれを伝え、「赤を反転」を用意しています。
  • シートはスプライト作業画面でフレームを切るまで1枚の絵としてライティングされます。テクスチャ作業画面ではフレームを切りません。
  • リムライトはプレビュー専用で、Unityにはスペキュラーマップを書き出しません(Godotには書き出し)。
  • Unityは独自の光の減衰を使います。書き出したノーマルマップはUnityで検証済みですが、明るさの曲線はUnityのものです。

バージョンと出典

判定の精度(convention_eval.mjs、2026-09-24):1Kの全体マップ128枚で100%正解、256²の切り抜きは判定を出したものの100%(判定率99.2%)、64²の切り抜きは99.6%、実在するスプライトのフレーム213枚で100%。赤を反転した同じフレームでも緑は100%正しく、213枚すべてで赤の反転を報告しました。1,562サンプルで誤った「高」判定は0件で、「緑が大半で高ければOpenGL」という単純な規則は46%でした。エンジンの規約はGodot・Unityのドキュメントに従います。

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

よくある質問

Godot・Unity・Unrealはどちらの規約?

GodotとUnityはOpenGL形式(Y+)、UnrealはDirectX形式(Y−)です。StudioのGodot 4とUnity 6向け書き出しはOpenGLで、Godot 4.7.2とUnity 6000.5.3f1で想定どおりに照らされることを確認しました。

判定はどれくらい当たる?

規約が分かっている実在のマップで測定:1Kマップ128枚で100 %、256²の切り出しは判定した分の100 %(99.2 %で判定)、64²は99.6 %、スプライト213フレームで100 %。1,562サンプルで誤った「高」判定は0件。「緑が明るければOpenGL」という単純な規則は46 %でした。

DirectXと分かっているなら緑を反転するだけでいい?

はい。下のリンクの従来のテクスチャ工房のページで緑を一度に反転できます。チェックパネルは確信のないファイル向けで、変える前にライティング結果を見せます。

赤が反転していると出るのはなぜ?

赤を逆に書く生成ツールがあります(NormalMap-Onlineの既定出力もそうです)。スプライトではシルエットで赤を別に測るため、判定は緑について、赤は別に報告し、信頼度は「中」までに抑えます。

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

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

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

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

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

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