How the conversion works
Neighboring height samples are compared in X and Y. Those slopes become the red and green normal channels, while the blue channel points away from the surface. Scharr gives stronger rotational symmetry; Sobel gives a familiar, slightly softer result.
Direction conventions
OpenGL uses +Y and DirectX uses −Y. Switching conventions flips the green channel only. Use OpenGL for Blender, Unity and Godot; use DirectX for Unreal Engine.
Prepare a useful height map
A height map represents relative elevation: black is low, white is high and gray values sit between them. Use smooth grayscale transitions for rounded forms and sharper transitions only where the surface actually changes abruptly. Remove color information, baked highlights and cast shadows before conversion because they can create slopes that do not belong to the material.
Leave enough tonal range to describe the surface without clipping broad areas to pure black or white. A noisy source often benefits from a small amount of Blur. A low-resolution height field cannot recover missing geometric detail, so begin with a source close to the intended texture resolution and judge the output at its final texel density.
Choose filter, strength and edge sampling
Scharr is a strong default for detailed height fields because its gradient response is comparatively balanced across directions. Sobel can be useful when the source is noisy or when a gentler result is desired. Increase Strength until the material reads under moving light, then back it down if highlights become harsh or the normal texture stops looking predominantly blue.
Use Repeat for a seamless texture so the left and right edges, and the top and bottom edges, are sampled as neighbors. Use Clamp for decals or non-tiling images. After export, import the normal map as linear data and tell the engine that the file is a normal texture rather than a color image.
Check the converted normal map
Test the plane preview with a directional light and verify that the same feature remains raised as the light moves. A reversed vertical response usually indicates the wrong OpenGL or DirectX convention. Visible seams indicate an untileable source or the wrong edge mode, while sparkling detail usually means the source noise or normal strength is too high.
Understand grayscale height values
A height map stores relative elevation in a single grayscale field. Black represents lower areas, white represents higher areas and gray values describe positions between them. The values do not define real-world centimeters by themselves; scale is established later by normal strength, bump distance, parallax settings or geometry displacement in the destination renderer.
Use smooth gradients for rounded surfaces and sharper changes only where the material has a genuine edge. Avoid large clipped regions unless the surface is intentionally flat at the minimum or maximum. A height image with good tonal separation gives the gradient filter useful slopes, while a posterized or crushed source creates stepping, harsh rings and unstable highlights in the converted normal map.
Prepare the height map before conversion
Remove color, baked shadows, reflections and camera lighting when the source began as a photograph. Correct perspective and tile seams before opening the converter. Keep enough resolution for the intended feature size, but do not preserve sensor noise that will disappear at normal viewing distance. A clean authored height field is more dependable than a dramatic image with unrelated tonal variation.
Check whether the source uses white-high or white-low semantics. If cavities appear raised, invert height once rather than compensating with a normal convention change; height inversion reverses both slope axes, while OpenGL versus DirectX changes only tangent Y. Keep an untouched master so each export variant can be reproduced without stacking destructive inversions.
How gradient conversion works
The converter samples neighboring height values in horizontal and vertical directions. Differences become the X and Y slope components of a tangent-space normal, and the vector is normalized to calculate blue. A flat region points mostly outward and appears blue; a height transition introduces red or green according to its direction. The result changes lighting direction without changing the mesh silhouette.
Because the calculation uses local differences, absolute brightness matters less than the relationship between neighboring pixels. A broad constant gray area can represent any baseline and still produce a flat normal. Abrupt one-pixel changes create steep directions, while gradual gradients create rounded lighting. This is why noise, banding and edge handling are visible in the final map even when the height image looks acceptable by itself.
Compare Sobel and Scharr gradients
Sobel is a familiar gradient operator with a slightly smoother character that can work well for soft surfaces and imperfect inputs. Scharr provides a more rotationally balanced response and is a strong choice for crisp authored height maps, diagonal forms and fine material detail. Both produce valid tangent-space directions and both remain dependent on source quality.
Compare them with identical Strength, Level, Blur and edge settings. Look at circular and diagonal features under moving light, then judge the result at the final UV scale. If one filter appears sharper only because it exaggerates noise, reduce source noise before deciding. Filter selection should improve consistent shape response rather than maximize visible texture at full zoom.
Balance level, blur and strength
Shape the height response before tuning the normal. Use Level or height controls to establish useful separation between low, middle and high areas. Add Blur sparingly to remove quantization, isolated pixels or capture noise before slope calculation. Too much blur merges nearby features and creates a swollen surface; too little can turn every pixel variation into a sharp lighting change.
Increase Strength until the intended relief reads clearly, then test from the actual camera distance. Excessive strength causes harsh highlights, visible compression and a normal texture with extreme red and green across broad areas. If a feature remains invisible at reasonable strength, its height gradient may be missing or its scale may be below the final texel density.
Choose Repeat or Clamp edges
Repeat treats opposite borders as neighbors and is appropriate for a height map already prepared to tile. It prevents the conversion filter from assuming that a tile ends at the image boundary. Clamp extends the border values outward and is safer for decals, stamps and non-repeating images. The wrong mode can create bright seams or a directional ridge around the texture perimeter.
Test tiling on a repeated plane with a moving light. A source seam must be repaired in the height field; Repeat only samples it consistently. Check every border at multiple scales and include mipmaps when validating in the destination engine. Unique baked assets also need padding around UV islands so filtering does not pull unrelated pixels into their normal edges.
Choose the destination normal convention
Export OpenGL (+Y) for Blender, Unity and Godot or DirectX (−Y) for Unreal Engine. These formats use opposite green-channel directions while preserving the horizontal red component and outward blue component. Select the preset for the receiving application and keep opengl or directx in the filename for a clear production handoff.
A simple moving-light test distinguishes a convention error from a height error. When only top-to-bottom slopes are reversed, switch the normal convention. When every raised area becomes a cavity, invert the height interpretation. When seams follow mesh triangles or mirrored UV islands, inspect the tangent basis, vertex normals and triangulation instead of editing image brightness.
Normal maps versus 16-bit height export
The converted normal map is suited to efficient surface lighting and normally exports as an 8-bit RGB data texture. It does not move geometry. Keep or export the height source separately when the destination needs bump, parallax or true displacement. A 16-bit height PNG provides more grayscale levels and can reduce visible stepping when smooth gradients deform sufficiently subdivided geometry.
Extra height precision does not automatically make a better normal texture, and a strong normal does not replace displacement where silhouettes must change. Use broad height for geometry-scale relief and normal mapping for finer shading detail, then verify that both describe the same raised and recessed forms. Establish displacement midpoint and scale inside the target material because the source contains relative elevation rather than physical units.
Troubleshoot and validate the result
Banding comes from limited or stretched height levels; ringing comes from sharp transitions or processing; sparkling often comes from noise, excessive strength or compression. A border ridge points to source continuity or edge mode. A reversed vertical response points to OpenGL versus DirectX. Diagnose one cause at a time with height, AO and other material effects disabled.
Import the normal as a dedicated Normal texture or Linear or Non-Color data, then test the actual mesh under several light directions. Review seams, glancing angles, mip levels and production compression. Preserve the original height map, filter choice and strength settings so the conversion remains reproducible when the target engine, shader or asset scale changes.
- White-high versus white-low is separate from +Y versus −Y
- Scharr favors balanced detail; Sobel offers a familiar softer response
- Repeat supports prepared tiles; Clamp supports isolated images
- Keep 16-bit height when displacement precision matters
