Skip to content

Normal Map OpenGL or DirectX — Detect the Green Channel

When bumps read as dents, or the light seems to hit a surface from the wrong side, the normal map's green channel is usually in the other convention: Godot and Unity expect OpenGL-style green (Y+), Unreal expects DirectX-style (Y−). File names and eyeballing get this wrong surprisingly often.

Drop a sprite, a sprite sheet or a tileable texture (PNG)
Runs in your browser. Files are not uploaded.
Studio Texture workspace: an imported ambientCG normal map read as DirectX with high confidence; nothing changes until the convention is confirmed
The real Studio with a CC0 asset (ambientCG).
Exports to
  • Godot 4 2D lightsVerified· Godot 4.7.2
  • Unity 6 URP 2DVerified· Unity 6000.5.3f1 (URP 17.5)
  • PNG set + JSONPlain files

What it does

  • The Check panel measures the convention from the surface itself: read as OpenGL, a real surface's slopes must be consistent with each other, and a DirectX map breaks that in a way that can be measured.
  • On sprites a second, independent test uses the silhouette: normals at the edge must face outward. Two tests that agree raise the confidence.
  • Every verdict comes with its confidence and evidence. A flat map without diagonal relief gets no verdict instead of a guess, and nothing is applied until you press It is OpenGL or It is DirectX.
  • A flipped red channel is caught on sprites and fixed with Flip red (X−). On a texture without transparent edges red and green cannot be told apart, and the panel says so.
  • Exports carry both conventions: _n (OpenGL) and _n_dx (DirectX) in the PNG set, or a single Normal map PNG in either one.

How to do it

  1. Drop the picture and its normal map into the Texture workspace.
  2. In the Normal map panel, set the source to the imported normal map.
  3. Open the Check panel and read the verdict, its confidence and the evidence.
  4. Press It is OpenGL or It is DirectX (plus Flip red (X−) if flagged), then compare flat and lit with C.
  5. Export the convention your engine reads, or the PNG set with both.

Which normal map for which engine

Engine or sourceGreen conventionFile to use from the Studio
Godot 4OpenGL (Y+)_n.png, or the Godot 4 bundle (CanvasTexture and a lit scene)
Unity (URP 2D)OpenGL (Y+)_n.png, or the Unity 6 bundle (Secondary Texture _NormalMap)
Unreal EngineDirectX (Y−)_n_dx.png
ambientCG downloadsNormalGL = OpenGL, NormalDX = DirectXTake NormalGL for Godot and Unity
A map of unknown originMeasured in the Check panelConfirm the verdict, then export either file
A sprite map with inverted redRed flipped (X−)Flip red (X−), then export

Engine exports and how each was checked

"Verified" means the exported files were loaded by the real engine or tool on real CC0 assets and the result was compared with the source. Anything that was not loaded is labelled as such.

TargetFilesCheck
Godot 4 2D lights_lit.tscn · CanvasTexture .tres · normal / specular PNGVerified Godot 4.7.2Six real CC0 cases rendered by Godot (gl_compatibility): every checked frame within 1/255 of the Studio's lit preview. The same render with green flipped is 3.8–37 levels off, so the check can see a wrong convention.
Unity 6 URP 2DPNG · nerulio-texture.json · Editor/NerulioNormalMapImporter.csVerified Unity 6000.5.3f1 (URP 17.5)12 of 12 runs (6 cases in Gamma and Linear colour space): the lighting URP applied matches the exported normal map (mean error 0.0037–0.0085). URP draws its own light falloff, so brightness is Unity's, not the preview's.
PNG set + JSONalbedo · _n (OpenGL) · _n_dx (DirectX) · 16-bit height · AO · specular · manifestPlain filesPlain files for any engine or tool; no engine run is claimed for them.

Evidence

Godot 4.7.2 rendered 6 real CC0 cases (pixel art, an HD sprite, a tileable texture, an imported DirectX map): every checked frame within 1/255 of the Studio's preview. Unity 6000.5 URP 2D: 12 of 12 runs pass (6 cases × Gamma and Linear). OpenGL/DirectX detection on real maps of known convention: 128 full 1K maps 100 % right, and not one wrong "high" verdict in 1,562 samples (a naive "green-high means OpenGL" rule gets 46 %).

Limits

  • On a picture without transparent edges (a tileable texture) a flipped red channel cannot be told apart from a DirectX green; the Check panel says so and offers Flip red.
  • A sheet is lit as one picture until its frames are cut in the Sprite workspace; the Texture workspace does not cut frames.
  • The rim light is preview only, and Unity gets no specular map (Godot does).
  • Unity draws its own light falloff: the exported normal map is verified in Unity, the brightness curve is Unity's.

Questions

Which convention do Godot, Unity and Unreal use?

Godot and Unity read OpenGL-style green (Y+); Unreal reads DirectX-style (Y−). The Studio's Godot 4 and Unity 6 exports write OpenGL and were rendered in Godot 4.7.2 and Unity 6000.5.3f1 with the expected lighting.

How often is the detection right?

On real maps of known convention: 128 full 1K maps 100 % right; 256² crops 100 % of the verdicts given (99.2 % got one); 64² crops 99.6 %; 213 sprite frames 100 %. No wrong "high" verdict in 1,562 samples. A naive "mostly green-high means OpenGL" rule scored 46 %.

I already know it is DirectX. Can I just flip green?

Yes. The classic Texture Lab page linked below flips green in one step. The Check panel is for the files you are not sure about, and it shows the lit result before anything changes.

Why does the panel say red is flipped?

Some generators write red inverted; NormalMap-Online's default output is one. On a sprite the silhouette measures red on its own, so the verdict is about green, red is reported separately and the confidence is capped at medium.

Is it free, and do I need an account?

Everything on these pages is free and works without an account. There is no watermark and no export that is held back.

Are my sprites uploaded?

No. The Studio decodes, packs and exports in this browser tab. Projects are autosaved in the browser (IndexedDB) and can be saved as a .nerulio file.

Does it need Aseprite or an engine plugin installed?

No. .aseprite files are read and written in the browser, and each engine bundle carries what that engine needs (for Godot, the import settings and scene; for Unity and the Godot TileSet, a small editor script).