Procedural Height Map To Normal Map (Shader Nodes) (world aligned normals)

Is there a way to convert a height map to a normal map in blender with shader nodes?
Like this image but all 3 axes.

This is how I’m getting the height:

Additional Info: I have a kilometer wide landscape and baking 16k normal textures isn’t a option. I’m trying to go Procedural and in world coordinates so I can later blend all objects because they should share the same normals.

I’d try either the Bump node or the Displacement node.

the Bump node does exactly what you describe - it takes a scalar and the existing normal, and produces a new normal.

The Displacement node does something similar, but you plug it into the Displacement output of the material. If you have Displacement turned on in the material settings, it will also displace the surface. If it’s turned to Bump Only (the default), then it will affect the value of Geometry>Normal (and the default normals of any built-in node that takes a Normal input).

However, there’s an issue with your existing setup: the Texture Coordinate>Object node doesn’t know anything about the terrain height map. It’s just telling you where the current surface’s position is in the empty’s object coordinates. You need to actually sample the height map when trying to convert it to a normal map, and can’t only evaluate the texture coordinates (which should be the input to the height map).

for those it seems like it just uses the pre existing normals per mesh to compute the normals and I need it to only use the image so all objects share the same normal:
currently:


Desired

Dang so id still need to use a image for this? thought id be possible with this procedural only setup

The process is simple but tedious…
All you need is to calculate the derivatives of the height map in both X and Y (Tangent and Bitangent of the UVMap).
That is: Sample the texture at P, at P+dx and at P+dy (for dx and dy small enough) and calculate the differences.
s = (Smp(P+dx) - Smp(P)) / dx
t = (Smp(P+dy) - Smp(P)) / dy
N' = N + (s * Tg) + (t * Bitg)
(thought the BumpMap node does exactly the same thing)

Not really.. If you specify the Normal vector (for example, to use a constant [0,0,1] for the whole object), it will then discard any mesh normals. It will just take the Tangent from the UVmap and transform it to the Normal you choose.

and if there is no uv map?

I see that it does work but it isn’t in world coords

It looks that it is in world space.
However, world space is not the same as the color space of NormalMaps.
NormalMaps are normalized to a [0, 1] range, while Normal vectors in world space are in [-1, 1].

If you want to transform Normal vectors in to NormalMaps, you need to multiply the Normal vector by 0.5 and add 0.5 to each axis.


Meshes - World Normals - NormalMap from [0,0,1]
(note in this example, there is a color transformation, and vector information is incorrect. For the correct result, you’d need to render without any color transformation, as raw)

They still aren’t “world” aligned coordinates though. Anyway, I’ve just gone with the using a image method since it is the simplest it seems.