How to gradually rotate a cube to face another cube that are both on a flat plane surface

Hi.

I have two cubes on a plane surface (which is their ground). I would like to gradually rotate cube 1 to face towards cube 2 and then move cube 1 towards cube 2. As they are both on the ground I figured I just need to rotate cube 1 on the y axis until it faces cube 2.

So far I have looked at rotateY, slerp, rotateTowards, and lookAt.

lookAt turns cube 1 towards cube 2 correctly, but it does it instantly, not gradually.

rotateY works in that it rotates parallel to the ground but I can’t figure out how to stop it when it faces in the direction of cube 2.

slerp and rotateTowards don’t seem to give the right result.

Is there a standard way of doing something like this, and if so, may someone provide an example?

Thank you very much for your time.

Quaternion.rotateTowards() is the intended method for this use case. Please show how you are using it in your code.

Thanks for your reply.
This is the start scene…

startingscene

If the cube is rotated on the z axis as shown in the code, the rotateTowards will orientate the model as if leaning over but also faces front still.

rotatetowards

I would like the model to face the cube by rotating on the y axis to emulate what you would do while standing on the ground. The intended end result should be…

intendedresult

The model should rotate to face the cube on the y axis regardless of how the cube is tilted.

My code is…

import * as THREE from './build/three.module.js';
		import { GLTFLoader } from './jsm/loaders/GLTFLoader.js';

        let scene, renderer, camera;
        let model;
        let cube;

        init();

        function init() {

            const container = document.getElementById('container');

            camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
            camera.position.set(0, 1.5, - 7);
            camera.lookAt(0, 0, 0);

            scene = new THREE.Scene();
            scene.background = new THREE.Color(0xa0a0a0);
            scene.fog = new THREE.Fog(0xa0a0a0, 10, 50);

            const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444);
            hemiLight.position.set(0, 20, 0);
            scene.add(hemiLight);

            const dirLight = new THREE.DirectionalLight(0xffffff);
            dirLight.position.set(- 3, 10, - 10);
            dirLight.castShadow = true;
            dirLight.shadow.camera.top = 2;
            dirLight.shadow.camera.bottom = - 2;
            dirLight.shadow.camera.left = - 2;
            dirLight.shadow.camera.right = 2;
            dirLight.shadow.camera.near = 0.1;
            dirLight.shadow.camera.far = 40;
            scene.add(dirLight);

            // ground
            const mesh = new THREE.Mesh(new THREE.PlaneGeometry(100, 100), new THREE.MeshPhongMaterial({ color: 0x999999, depthWrite: false }));
            mesh.rotation.x = - Math.PI / 2;
            mesh.receiveShadow = true;
            scene.add(mesh);

            const loader = new GLTFLoader();
            loader.load('/my-app/src/app/scene-models/Soldier.glb', function (gltf) {

                model = gltf.scene;
                model.position.set(0, 0, 0);
                scene.add(model);

                model.traverse(function (object) {

                    if (object.isMesh) object.castShadow = true;

                });


                animate();

            });

            renderer = new THREE.WebGLRenderer({ antialias: true });
            renderer.setPixelRatio(window.devicePixelRatio);
            renderer.setSize(window.innerWidth, window.innerHeight);
            renderer.outputEncoding = THREE.sRGBEncoding;
            renderer.shadowMap.enabled = true;
            container.appendChild(renderer.domElement);

            const geometry = new THREE.BoxGeometry(1, 1, 1);
            const material = new THREE.MeshNormalMaterial();
            cube = new THREE.Mesh(geometry, material);
            cube.position.set(3, 0, 0);
            cube.rotateZ(.5);
            scene.add(cube);

            window.addEventListener('resize', onWindowResize);

        }

        function onWindowResize() {

            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();

            renderer.setSize(window.innerWidth, window.innerHeight);

        }

        function animate() {

            requestAnimationFrame(animate);

            if (!model.quaternion.equals(cube.quaternion)) {
                model.quaternion.rotateTowards(cube.quaternion, .01);
            }

            renderer.render(scene, camera);

        }

Any further help is greatly appreciated.

Try it like so: https://jsfiddle.net/r6j7yLea/1/

Notice that the solider model is no good asset for this use case since when no rotation is applied, it looks along the negative z axis. This is not the default of 3D objects in three.js where it is the positive z axis. Hence, the model should be corrected in Blender before using it like in the fiddle.

Apart from that, it is important that the target point and the model’s position lie in the same conceptual y-plane.

Phenomenal!

I have applied this and it works perfectly.

Thank you very much!

1 Like