I was trying to export a heightmap from landscape built in unreal and create a layer of which the shape is identical to the landscape with this heightmap. So I made a plane and applied the heightmap to the material’s world position offset. Finally I managed to do this but I took some tricks which I actually didnt understand why.

First I subtracted the red channel by 0.5, otherwise the plane which I applied the material would be ‘moved up’ by some distance.

Then I multiplied the result above by 65536 —— which I do understand, since the heightmap uses a G16 format, so the [0, 1] red channel needs to be restored to original value.

Finally I multiplied the result above by about 0.788 to get the plane right fit to the landscape.

I double checked the texture to ensure the ‘sRGB’ is not checked, and I switched several compression settings (Vector Displacementmap, Alpha) but still get the same result.

Thing is, what I want to do actually is to make a top boundary for raymarching my fog that flows on this landscape, and I know that this top boundary doesn’t need to fit the Landscape perfectly but, just out of curiosity I still wondered the reason or if I made some mistakes during this procedure.

Does the planes geometry match the landscapes individual quad size exactly?

The reason you had to subtract 0.5 is because the alpha height map texture is 0 to 1 so subtracting 0.5 makes it -0.5 to 0.5. The way to remap the 0 to 1 to -1 to 1 is to subtract 0.5 and then multiply by 2. There is a node inside the material editor that does this sort of add/multiply calculation called ConstantBiasScale. You can use it to remap 0 to 1 to -1 to 1 and -1 to 1 back to 0 to 1. To do that just add one and multiply by 0.5.

Yes the landscapes range is 65536 for the G16 format. They are integers.

The scaling of a landscape is usually ackward for me to get right too. I seem to remember if the landscapes transform scale is 100, 100, 100 then essentially what the landscape is, is a cube with the landscape surface at the center and the vertical 65536 stretched across the cubes z axis. Since your plane will also be 100, 100, 100 then the -1 to 1 remap makes it stretch to fill that cube (vertically). By multiplying it your scaling that range down until it matches. Of couse the height map that was captured is not 0 to 1 fully so in there is a shade of grey. This is maybe where the “multiply by 2” may help to get it fully remapped to -1 to 1 rather than -0.5 to 0.5.

I have not tested any of this so just adding my two cents and hoping it helps.

Check out my video here for USurfaceMesh plugin on the marketplace:

I know you’re trying to displace using the GPU world position offset, where as USurfaceMesh actually displaces using actual CPU geometry but I thought this video might help anyway.

Hi 3dev, Thank you so much and sorry for my delayed reply. What you presented in the video is amazing and is such a useful tool. I thought over about the ‘landscape scale’ issue you mentioned and I figured out the coeffecient 0.788 in my third step might actually be 2 * 100 / 253 = 0.7901, where the 2 is for mapping height range from [-0.5, 0.5] to [-1, 1] as you presented, 100 is the scale and 253 is the resolution of my landscape (also the grid size of my plane). So by now these numbers seem to make sense.

I did another trial just now, with a 505 x 505 landscape and a plane with 505 x 505 vertices, but unexpctedly the ‘pipeline from heightmap sample to world position offset’ is:

offset = ( height - 0.5 ) * 2 * 100 / 253;

I expected the divisor to be 505, actually I dont understand why the height need to be divided by 253 here, and now this number seem to be fixed ? I will do further tests with other resolutions.