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.
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>