It's all fine and dandy moving vehicles around the level, heading in the correct direction and at the correct height based on the tile underneath. But when it encounters a hill/dune/bump it shouldn't just float up and float down, the vehicle's orientation should change with it's nose point towards the sky as it mounts the slope.
It was easy enough reading the normal from the currently occupied face. But I had some trouble getting the measurements to work correctly according the vehicle's local axis, as opposed to the world axis. This means that if the vehicle is heading north-east, it's local axis is turned 45 degrees (or Pi over 4 :P) from the world axis. But in essense I ended up with a value that I could use to stick into the world matrix for the vehicle.
The green (tangent) vector here is the key. You cannot work with the normal, because it has no relation to the direction. I initially used the red (normal) vector to calculate an angle with the Unit Y vector, because irrespective of direction, Unit Y is still applicable to the vechicle's local axis. But in fact that was wrong. The direction is important, and the calculation of the tangent to use in conjunction with the vehicle's own direction vector is the key. In the image below the magenta lines are the face normals, and the green lines are the tangent normals.
So that solved the tilt angle, but as you can see, I still need to do the roll-angle. Hopefully this won't take me as long.