Search code examples
javascriptthree.jstransformationcoordinate-transformationnormals

Meaning of this code snippet in three JS


As I am new in the 3D world and three JS world, I understood most of the things, but always gets confused when it comes to matrices.

What I am trying to do is that I want to drag a small object on top of other objects and small object should face the same direction of the main object (an example is like hanging a wall clock on the wall).

To do this, I first tried placing an axis helper on top of rotating cube and applied the simple logic that, an Intersecting point will give the position for putting a small object and intersecting objects face normal will give direction for small object lookAt. I did and found success but not appropriate.

Then I did some calculation and searched some codes for calculating the same things, I got success now. But didn't understand the whole logic behind, WHY we did this.

this.normalMatrix.getNormalMatrix(intersects[i].object.matrixWorld);
this.worldNormal.copy(intersects[i].face.normal).applyMatrix3(this.normalMatrix).normalize();
this.object.position.addVectors(intersects[i].point, this.worldNormal);
this.lookAtVec.addVectors(this.object.position,this.worldNormal.multiplyScalar(15));
this.object.lookAt(this.lookAtVec);

One guy actually created a wall and placed a small object on top. He changed this line

this.object.position.addVectors(intersects[i].point, this.worldNormal);

to

this.object.position.copy(intersects[i].point);

and it is working for him, but the same thing for my axis helper is not working.


Solution

  • Just an option of how you can do it. Look at the end of the onMouseMove() function:

    var scene = new THREE.Scene();
    var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
    camera.position.set(-3, 5, 8);
    camera.lookAt(scene.position);
    var renderer = new THREE.WebGLRenderer({
      antialias: true
    });
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setClearColor(0x404040);
    document.body.appendChild(renderer.domElement);
    
    var controls = new THREE.OrbitControls(camera, renderer.domElement);
    
    var light = new THREE.DirectionalLight(0xffffff, 0.5);
    light.position.setScalar(10);
    scene.add(light);
    scene.add(new THREE.AmbientLight(0xffffff, 0.5));
    
    var walls = [];
    
    makeWall(Math.PI * 0.5);
    makeWall(0);
    makeWall(Math.PI * -0.5);
    
    var clockGeom = new THREE.BoxBufferGeometry(1, 1, 0.1);
    clockGeom.translate(0, 0, 0.05);
    var clockMat = new THREE.MeshBasicMaterial({
      color: "orange"
    });
    var clock = new THREE.Mesh(clockGeom, clockMat);
    scene.add(clock);
    
    var raycaster = new THREE.Raycaster();
    var mouse = new THREE.Vector2();
    var intersects = [];
    var lookAt = new THREE.Vector3();
    
    renderer.domElement.addEventListener("mousemove", onMouseMove, false);
    
    function onMouseMove(event) {
    
      mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
      mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
    
      raycaster.setFromCamera(mouse, camera);
    
      intersects = raycaster.intersectObjects(walls);
      if (intersects.length === 0) return;
    
      clock.position.copy(intersects[0].point);
      clock.lookAt(lookAt.copy(intersects[0].point).add(intersects[0].face.normal));
    }
    
    render();
    
    function render() {
      requestAnimationFrame(render);
      renderer.render(scene, camera);
    }
    
    function makeWall(rotY, color) {
      let geom = new THREE.BoxBufferGeometry(8, 8, 0.1);
      geom.translate(0, 0, -4);
      geom.rotateY(rotY);
      let mat = new THREE.MeshLambertMaterial({
        color: Math.random() * 0x777777 + 0x777777
      });
      let wall = new THREE.Mesh(geom, mat);
      scene.add(wall);
      walls.push(wall);
    }
    body {
      overflow: hidden;
      margin: 0;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/94/three.min.js"></script>
    <script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>