Search code examples
javascriptvectorthree.jsrotationnormals

How to make an Object3D's face look at another face (eg. floor) by rotating the object


Sitation

A scene with a floor and an object that floats directly above it.

What I am trying to do

When I click on a face of an object I want the whole object to rotate in such a way that the clicked face faces the floor.

What I have tried so far

  1. Click on any object's face: Raycaster picks up the first face.
  2. replace the object's up vector with the normal of the clicked face: object.up.copy(face.normal)
  3. call object.lookAt(floor.position)

I would expect that because of the new up vector, the object would lookAt the floor with an orientation based on the clicked face.

However, The rotation doesn't work as expected. What am I missing?

The relevant code part:

var intersects = raycaster.intersectObject( cylinder );
    if(intersects === undefined || intersects.length === 0) return;


    let face = intersects[0].face;

    // Set cylinders up to the normal of the intersected face to reoriented object
    // to make the clicked-on face `lookAt()` the floor:
    cylinder.up.copy(face.normal);
    cylinder.up.normalize();
    cylinder.lookAt(floor.position);

The whole code

http://codepen.io/anon/pen/EWRdZq

(UPDATE) The Fixed code

Based on @WestLangley's answer: http://codepen.io/anon/pen/ryZOvx


Solution

  • You want to rotate an object so that a face's normal points in a particular direction.

    In your example, the desired direction is in the direction of the negative-y axis, but you could specify any direction vector, as long as it has unit length.

    You can use a pattern like so:

    let direction = new THREE.Vector3( 0, - 1, 0 ); // create once and reuse
    
    ...
    
    let object = intersects[ 0 ].object;
    let normal = intersects[ 0 ].face.normal;
    
    object.quaternion.setFromUnitVectors( normal, direction );
    

    Note that your problem statement does not have a unique solution. For example, the object can be "spun" on an axis and still have the face oriented in the desired direction.

    three.js r.84