Skip to content

Godot 2D Normal Map — Export a Lit Sprite Scene for Godot 4

In Godot 4 a 2D normal map does nothing on its own: it has to sit in a CanvasTexture, and a Light2D has to reach the sprite from some height. The Texture workspace generates the map, lights it with the formula Godot's canvas renderer uses, and exports the finished scene — sprite, lights, ambient colour and frames — which Godot 4.7.2 rendered within 1/255 of the preview.

Drop a sprite, a sprite sheet or a tileable texture (PNG)
Runs in your browser. Files are not uploaded.
Studio Texture workspace: a pixel-art torch cut into 6 frames, lit by a point light with its generated normal map
The real Studio with a CC0 asset (OpenGameArt).
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

  • <name>_lit.tscn: a Sprite2D whose texture is a CanvasTexture (diffuse + normal), a CanvasModulate for the ambient colour, one PointLight2D per light and, for a cut sheet, an AnimationPlayer that steps region_rect through the frames.
  • Each PointLight2D carries the light's own falloff (smooth, linear, quadratic or none) as its texture, plus its colour, energy and height — the z you set in pixels.
  • <name>_canvas_texture.tres for your own Sprite2D; when specular is above 0, a specular map and specular_shininess are added to it.
  • The Lit view uses Godot's canvas light model — base × ambient + falloff × light × energy × (base × N·L + specular) — and the WebGL2 view equals the CPU reference within 1/255.
  • Up to 8 point lights. The rim light stays in the preview, because Godot draws none without a custom shader.

How to do it

  1. Drop the sprite or sheet; cut a sheet in the Sprite workspace first so its frames animate.
  2. Check the bevel and detail in the Normal map panel and raise or lower relief with the Height brush (B).
  3. Press L, place the lights, set height, energy and falloff, then press Enter in the Lit view to play it.
  4. Export (Ctrl+E) with Godot 4 ticked.
  5. Copy the godot folder anywhere under res:// and open <name>_lit.tscn.

What the Godot bundle contains

File or nodeWhat it holdsWhat to do with it in your game
Sprite2D in <name>_lit.tscntexture = the CanvasTexture, region enabled, Nearest filter for pixel artInstance the scene, or copy its texture onto your own sprite
<name>_canvas_texture.tresdiffuse_texture, normal_texture, optional specular_texture and specular_shininessReuse it on any Sprite2D that draws the same sheet
PointLight2D (one per light)Position in frame pixels, color, energy, height = z, falloff PNG as texture, texture_scale from the radiusKeep one as a torch, delete the rest, or copy the numbers to your level lights
CanvasModulate "Ambient"The ambient colourKeep a single one in your level; it tints the whole canvas
AnimationPlayerOne animation per tag, region_rect keys at each frame's start, looping as taggedCall play() with the tag name from your script
PNG files<name>.png, <name>_n.png (OpenGL), specular map, one falloff PNG per falloff usedKeep them next to the scene; the paths are relative

Not exported: the rim light (preview only). The README in the folder repeats the verification status.

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

My normal map has no visible effect in Godot 2D. What is missing?

Usually one of three things: the map is not set as the CanvasTexture's normal_texture, no Light2D reaches the sprite, or the light's height is left at 0 so it only grazes the relief from the side. The exported scene has all three set, so compare your node with it.

Does the bundle use AnimatedSprite2D?

No. It animates a Sprite2D: an AnimationPlayer moves region_rect over the sheet, and one CanvasTexture holds the normal map for every frame. That is the setup Godot 4.7.2 rendered in the check; an AnimatedSprite2D setup was not part of it.

Which renderer and assets was it checked with?

Godot 4.7.2 on the Compatibility renderer (gl_compatibility), six real CC0 cases: a pixel torch with and without specular, a 60-frame samurai, an 80×110 adventurer, a tileable brick texture and an imported DirectX map. Every checked frame was within 1/255; the same render with green flipped was 3.8–37 levels off.

Will Godot's brightness match the preview?

Yes: each light carries the Studio's falloff as its texture, so the curve is the same, and the check compared the final lit pixels. Unity differs — URP draws its own falloff.

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).