Texture Map Lab

Create grayscale, alpha, inverted and height-gradient normal maps.

A normal map generator turns a height or grey image into a tangent-space normal map: for every pixel it measures how steeply the height rises left–right and up–down and writes that tilt as RGB, with flat areas at exactly (128, 128, 255). This page opens the Texture Lab: drop a height map, a grey texture or a sprite, pick brightness or alpha as the height, a Sobel, Scharr or Sobel 5×5 kernel, a strength and OpenGL (Godot, Unity) or DirectX green, and download the PNG. It runs in the browser; nothing is uploaded.

Drop image files hereProcess many files at once
No upload · processed on this device

From height to normal: gradient, kernel and strength

The Lab reads one height value per pixel: either the brightness of the image (Rec. 709 luma, 0.2126 R + 0.7152 G + 0.0722 B) or its alpha channel, from 0 to 255, used as 0 to 1. White is high, black is low.

A derivative kernel estimates the slope in x and in y from the neighbouring pixels. Sobel 3×3 is the default; Scharr 3×3 weighs the centre row more, which keeps diagonal slopes more consistent; Sobel 5×5 averages over a wider area, which calms noise and loses fine detail. Every kernel is normalised so that a ramp of one full height unit per pixel reads as slope 1, so the same strength gives the same tilt whichever kernel you pick.

The normal is (−strength·∂h/∂x, strength·∂h/∂y, 1) normalised to length 1 and encoded as (n + 1) × 127.5; DirectX output negates green, which is the only difference between the two files. With Wrap on, the kernel samples across the opposite edge, which a repeating texture needs; with Wrap off the border pixels are clamped and a tiled copy shows a seam.

Height map
A grey image where white is high and black is low.
Kernel
The small grid of weights that estimates the slope from neighbouring pixels.
Strength
The slope multiplier: 0–10 on the slider, 2 by default.
Wrap
Sampling across the opposite edge, so a tileable map has no seam.

Example: a brightness ramp of 32 levels per pixel

A grey image that gets 32 levels brighter per pixel towards the right, Sobel 3×3, OpenGL:

slope = 32 / 255 = 0.1255 per pixel
strength 1:  n ∝ (−0.1255, 0, 1) → (−0.124, 0, 0.992) → RGB (112, 128, 254)   tilt  7.2°
strength 2:  n ∝ (−0.2510, 0, 1) → (−0.243, 0, 0.970) → RGB ( 96, 128, 251)   tilt 14.1°
flat area:   n = (0, 0, 1)                            → RGB (128, 128, 255)

Red drops below 128 because a surface rising to the right faces left. Doubling the strength does not double the tilt, because the vector is normalised again: tilt = atan(strength × slope).

Check the result

  • Flat parts of the height image must come out exactly (128, 128, 255); the Lab tests this for all three kernels and both conventions.
  • Read the validation under the result: mean vector length close to 1.000 and blue never below 128, since a normal cannot point into the surface.
  • For a tileable texture, check the joins with Wrap on, for example with the tiling seam check.
  • Light it before you ship: in your engine, or in the Lab's material preview, which is labelled an approximation (one light, GGX).

Troubleshooting

SymptomLikely causeHow to checkFix
Bumps look like dentsIn this picture dark is raised, but the Lab reads dark as lowA known bump: its lit side faces away from the lightTick both Invert X (red) and Invert Y (green) (the same as inverting the height); if only up–down is wrong, switch the convention instead
A line appears where the texture repeatsWrap was off, so the border pixels were clampedTile the result 2 × 2 and look at the joinsTurn Wrap on and export again
Grainy, noisy reliefJPEG artefacts or painted texture read as heightZoom into areas that should be smoothUse a PNG source, Sobel 5×5 or a lower strength
A sprite's outline stays flat while its inside is bumpyBrightness has no bevel: the silhouette is height only when alpha is the sourceSwitch the source to Alpha and compareUse alpha as height, or the bevel in the sprite normal map generator

Other ways to do it

OptionWhen it is the better choice
Studio Texture workspace (sprite normal maps)Sprites: a bevel from the silhouette, lights computed like Godot, per-frame sheets and verified Godot 4 and Unity 6 exports.
Bake from a high-poly model in a 3D programThe surface exists in 3D: a bake gives true normals instead of a guess from brightness.
OpenGL ↔ DirectX converterYou already have a normal map and only need the other green convention.

What this page does not cover

  • Brightness is not shape: painted shadows become dents and painted highlights become bumps.
  • No bevel, no 2D light preview and no engine bundle here; these maps were checked numerically, not rendered in an engine.
  • Output is an 8-bit PNG; a 16-bit height input keeps only its high byte.

Versions and sources

Texture Lab, measured on downloaded files: generated and converted maps decode to unit vectors (mean length 1.0001, worst deviation 0.0002); a flat height gives (128, 128, 255, 255) with all three kernels and both conventions; a wrapped edge equals the same pixel inside a real 2 × repeat; OpenGL and DirectX outputs differ in green only (255 − g). The Y+ convention of Unity and Godot is taken from their documentation.

Official documentation used

Example

Original geometric sample · 96 × 64
Original geometric sample · 96 × 64
Processed sample · 96 × 64
Processed sample · 96 × 64

Example generated with this tool. ZIP tools show their preview; inspect the downloaded archive for every file.

Texture Map Lab

Create grayscale, alpha, inverted and height-gradient normal maps.

How it works

  1. Add images
  2. Adjust settings and review the result
  3. Download a new file

Supported formats

PNG / JPG / WebP / AVIF / HEIC → PNG — Input decoding depends on browser support and optional engines.

What this tool does

Create grayscale, alpha, inverted and height-gradient normal maps.

Implementation and verified quality

advanced · overlapped tiles / luminance height gradient. Quality qualification is in progress. Pro/Flagship quality has not been established.

Before you export

Normals approximate image luminance as height; they do not reconstruct geometry or PBR materials.

Frequently asked questions

What are this tool’s limitations?

Normals approximate image luminance as height; they do not reconstruct geometry or PBR materials.

Are my files uploaded?

This tool processes the files you open on your device without uploading them. Images you explicitly attach to community posts are uploaded separately. Optional engines and models are downloaded from third parties; those requests expose connection information such as your IP address.

Will my work be saved automatically?

No. Images and editing state stay in this tab; media output can use local temporary storage. Changing language preserves your work; reloading, closing the tab, or following a link to another page can clear it.