Converting Height Maps From Colour to Grayscale

heightMapDemo.png

Height maps are typically used for distorting geomtery via texture displacement or mesh displacement to describe the relief of a landscape. Maps are usually stored as 8-bit image files rather than floating-point 16 or 32-bit for compression purposes. In order to maximise the resolution of the height data being stored, people typically encode their maps using colour rather than grayscale. The thinking behind this being that an 8-bit image can only store 0-255 (256 total) different tones per channel, and flooding each channel with the same data in order to create a grayscale image is a waste of valuable space. It’s more efficient to spread the data over all three channels to maximise fidelity.

The example below is a colour height map describing rivers, flat land and mountains. Sourced from here.

color-1024x1024.jpg

The issue arises however when you receive a map in this format (pictured above) and you need to convert it back to grayscale for displacement. There are lots of forum posts on the web with people discussing this and unfortunately too often I see replies telling people to “just use the red channel” or “desaturate and grade the image until it looks right”. This is just wrong. You might get something that looks okay but it’s never going to be as accurate as converting it correctly - there’s a load of detail between red and blue that is important to capture.

Method

We need to disregard saturation and luminance for now and look purely at hue. The range in hue is how the data is being distributed which means we need to isolate it from the saturation and luminance. We’ll need to convert to HSV (hue, saturation, value) colour space. If converting using a floating point software like Nuke then your gamma encoded map should have already been converted to linear space. However for non-linear spaces you’ll need to invert your gamma encoding prior to the conversion.

Due to the cyclical way hues are mapped in the HSV space, red is equal to 0 and 360 - all other colours will lie between that range. Coloured height maps typically map the lowest furrows in the landscape to blue, meaning that when converted to HSV, blue will actually be bright and red black. If you had a ramp showing the entire spectrum from red through green, blue and back to red again, the hue would be represented as a linear ramp from 0-1. However if a source image only ranges from red through green to blue (like height maps), only 2/3 of the range is covered. This means that the output grayscale ramp will range from 0-0.66666. We’ll need to normalize it by dividing 1 by 0.66666 to get the quotient (1.5). This will probably need some modification depending on the situation, as not all situations will require normalization.

The range can then be inverted to produce a positive displacement map with red extruding the most and blue the least. To offset the baseline of the displacment such that blue subtracts and red adds, minus 0.5 from the map and multiply by 2.

Converting to HSV

I stumbled across a write-up on HSV by Nikolai Waldman here

HSV Using Photoshop

There’s a cheap method for converting an image to a hue space using Photoshop, illustrated by someone here. I haven’t tried it myself, but in their words:

Set the image layer's Blend Mode to Hue, add a layer below it filled with pure red (#ff0000, or any other fully saturated colour).

Previous
Previous

Nuke’s Grade Node Demystified

Next
Next

Fit Functions and Blackpoint / Whitepoint Adjustment