How to get vector perpendicular to the displacement map plane in three.js?

In three.js I draw a map using displacementMap option. Like this


// ADD CAMERA
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.up.set( 0, 0, 1 );
camera.position.set(GAME_CONTEXT.camera_init_position.x, GAME_CONTEXT.camera_init_position.y, GAME_CONTEXT.camera_init_position.z); 
camera.lookAt(Utils.GetCameraLookAtDirection(GAME_CONTEXT, camera));

// ADD MAP
const loader = new THREE.TextureLoader();
const height = loader.load(GAME_CONTEXT.height_map_link);
const texture = loader.load(GAME_CONTEXT.texture_map_link);
const normal = loader.load(GAME_CONTEXT.normal_map_link);
const map_geometry = new THREE.PlaneBufferGeometry(GAME_CONTEXT.width, GAME_CONTEXT.height, 64, 64);
const map_material = new THREE.MeshStandardMaterial({
    color:'orange',
    //side: THREE.DoubleSide,
    map:texture,
    displacementMap: height,
    displacementScale: GAME_CONTEXT.scale,
    normalMap : normal
    //alphaMap: alpha,
    //transparent:true
});
const map_plane = new THREE.Mesh(map_geometry, map_material);
map_plane.position.x += GAME_CONTEXT.width/2;
map_plane.position.y += GAME_CONTEXT.height/2;
scene.add( map_plane );

Now if I have a (x,y,z) coordinate in the game world (the z is the surface height of the displacement map at (x,y)), how can I calculate the normal vector representing to this point on the map?

Like in this image, if the yellow part is the surface of the terrain in the displacement map, then I want the vector in red as normalized too.

How can one calculate this?

In this image, lets say the yellow square is a a small square tile centered on the (x,y) point, then the red vector is what I am looking for.

/cc

The answer there did not help at all.

Assuming this yellow square patch has corner vertices v1, v2, v3, v4, compute any two non-parallel in-plane vectors, for instance:

a = v1 - v2
b = v1 - v3

Then you’ll get a normal vector as the cross product of the two:

n = a X b

The normalized normal is

n / Math.sqrt( n.x * n.x + n.y * n.y + n.z * n.z )

1 Like

And the square patch will have two normals, as there will be two triangles. Also, all four vertices can be non-complanar, thus, there will be two non-collinear normals.

1 Like

Correct - thanks for pointing this out.

To further clarify, for each triangle the

have to come from the same triangle. So in my above example

a = v1 - v2
b = v1 - v3

v1 must not be one of the endpoints of the diagonal which splits the quad into two triangles.

For the sake of completeness only as a supplement:


Very often, the reverse problem also occurs in this context.

There is an elegant solution for this - unfortunately not from me. But I use it in my addon

THREEf.js/THREEf.js at cc28a353fe8e3a6e98956dc299d1762b178ad452 · hofk/THREEf.js · GitHub

Line 1771


if ( i === 0 ) {  // first binormal 

// see  http://lolengine.net/blog/2013/09/21/picking-orthogonal-vector-combing-coconuts

Shaders usefulness ends with their visual effects.
What you need is to create new vertex coords base on pixel value of heightmap texture presented by its uv coords.

If you do you not know how to do that, start a new threat.