IMG · Images tools

Normal Map Generator

Shareable link

Settings are written to the URL as you change them. Nothing differs from the defaults yet.

A normal map stores the direction a surface faces at every pixel, packed into RGB. A renderer reads it to shade flat geometry as if it had grooves, bumps, and grain, without adding a single polygon. Drop in a heightmap or a texture photo and the generator measures the slope at each pixel and writes that direction out as a tangent-space map.

From height to slope

The input is read as a height field: white is high, black is low. For each pixel a 3×3 kernel compares the heights on either side, horizontally and vertically, which gives the slope in X and Y. The surface normal is the vector perpendicular to those two slopes, normalized to length 1.

The vector components run from -1 to 1, and they are remapped to 0-255 for storage:

  • Red is the X slope. Values above 128 lean right.
  • Green is the Y slope. Which way it leans depends on the convention.
  • Blue is Z, the part facing straight out. Flat areas sit at 128, 128, 255, the familiar lavender of an untouched normal map.

OpenGL vs DirectX green

The two conventions disagree on one thing: whether green means up or down. OpenGL (Y+) is the default in Blender, Unity, and Godot. DirectX (Y−) is the default in Unreal Engine and 3ds Max.

Load a map in the wrong convention and the lighting on one axis inverts: bumps read as dents when the light comes from above. The fix is the Green channel setting, not a re-render of the source.

Strength and smoothing

Strength scales how steep each slope reads. Low values give a subtle grain; high values push edges toward sideways-facing normals, which look harsh under a raking light.

Smoothing blurs the height field before the slope is measured. It is set as a percentage of the shorter image side, so the preview and the full-resolution export match. A radius of 0.3% on a 2048px texture is about 6px, enough to remove JPEG blocking without erasing fine cracks.

The two controls work against each other. Smoothing removes small detail and lowers apparent depth, so raise Strength afterward to compensate.

Height channel and inversion

Height from picks which channel becomes the height field. Luminance suits photos and grayscale heightmaps. A single channel suits packed textures, where one image stores roughness, height, and occlusion in separate channels. Alpha reads the height stored in a PNG’s transparency.

Invert height flips high and low. Use it when the source is a depth map that stores distance from the camera instead of height, or when a photo’s grout lines are lighter than its tiles.

Photos as a source

A photo works when brightness tracks surface height: stone, bark, concrete, fabric, plaster. It fails where brightness has nothing to do with shape. Cast shadows become false ridges, printed text becomes embossed lettering, and a dark knot in wood becomes a pit.

Flat, diffuse lighting gives the best source. Shoot under overcast sky or a softbox, and avoid direct sun, which bakes one light direction into the texture before the normal map adds another.

Seamless textures

A tileable texture stays tileable only if the slope at each border is measured against the opposite border. Tileable edges wraps the sampling around the image so the normal map has no seam when repeated. Leave it off for a one-off image: wrapping would compare the left edge against unrelated pixels on the right and draw a ridge along the border.

Frequently Asked Questions

It reads a JPEG, PNG, or WebP image as a height field, measures the slope at every pixel, and writes the surface direction as RGB: red for X, green for Y, blue for Z. The result is a tangent-space normal map you can plug into the normal slot of a material in Blender, Unity, Unreal, or Godot.

Match the engine. Blender, Unity, and Godot read OpenGL maps, where green points up. Unreal and 3ds Max read DirectX maps, where green points down. If lighting looks lit from below on one axis, the green channel is flipped, so switch the setting and export again.

Slopes are derivatives, and a derivative amplifies sensor noise and JPEG blocking as much as real surface detail. Raise Smoothing until the speckle flattens, then raise Strength to bring the depth back.

Yes, but the result assumes bright means high and dark means low. That holds for many surfaces like stone, bark, and plaster, and fails where color changes without the surface changing, such as painted lines or shadows. A grayscale heightmap gives a more accurate result.

Each pixel stores a vector, not a color. JPEG compression shifts those values in 8×8 blocks, which shows up as faceted shading in the render. PNG keeps every value exactly.

It treats the image as wrapping around, so the slope at the right edge is measured against the left edge, and the top against the bottom. Turn it on for seamless textures; leave it off for a one-off image, or a hard seam appears where unrelated edges meet.

Explore Our Tools

Browse all tools