0

I am encountering rotation issues in THREEJS where my object (From blender, gltf.scene) totations are extremely unpredictable and inconsistent. I want my object to spin like a ballerina when the mouse moves (depending on the x coordinates of the mouse, the object will spin: anticlockwise when the mouse moves to the right and clockwise when the mouse moves to the left).

There are two points in my code where I rotated my object 1) initially when I imported my model and 2) in the tick function (so it moves like a ballerina accordingly to the position of the mouse).

This is the main part of my issue: Sometimes when I load my page it does exactly what I want. However, sometimes when I reload the page the object might not even rotate, and I can reload the page and my object will be fine again. I searched online for similar issues already and I believe it is due to Gimbal Lock. I am unsure how to fix my code so my rotations are not inconsistent. I also have a imageMesh object created in THREEJS that will spin in the same manner as my object imported from blender and this object never has the rotation issue present in gltf.scene object.

Code From Initially Loading The Object

// Load GLTF Model
    gltfLoader.load(
        '/Trial8.glb',
        (gltf) => {
            modelRef.current = gltf.scene;
            gltf.scene.traverse((child) => {
                if (child.isMesh) {
                    child.geometry.center(); // Centers the geometry relative to its local origin
                    child.material = bakedMaterial;
                    child.castShadow = true;
                    console.log('Model material:', child.material.constructor.name);
                }
            });
            gltf.scene.position.set(1.5, -7.54, 3);

            // Set initial rotation using Quaternion to avoid Euler issues
            const initialQuaternion = new THREE.Quaternion();
            initialQuaternion.setFromEuler(new THREE.Euler(0, -Math.PI / 2, Math.PI / 2, 'XYZ'));
            gltf.scene.quaternion.copy(initialQuaternion);
            gltf.scene.scale.set(0.5, 0.5, 0.5);
            scene.add(gltf.scene);

            // Add AxesHelper to visualize origin
            const axesHelper = new THREE.AxesHelper(1); // 1 unit long, scaled with model (0.5)
            gltf.scene.add(axesHelper);
            

            const originMarker = new THREE.Mesh(
                new THREE.SphereGeometry(0.1),
                new THREE.MeshBasicMaterial({ color: 0xff0000 })
            );
            originMarker.position.set(0, 0, 0);
            modelRef.current.add(originMarker);
        },
        (progress) => {
            console.log(`Loading: ${(progress.loaded / progress.total * 100).toFixed(2)}%`);
        },
        (error) => {
            console.error('Error loading GLTF:', error);
        }
    );

Code in Tick Function

// Animation loop
    const clock = new THREE.Clock();
    const tick = () => {
        const elapsedTime = clock.getElapsedTime();

        if (cameraRef.current) {
            const targetX = mouse.x * moveRange;
            const targetZ = -mouse.y;
            cameraRef.current.position.x = THREE.MathUtils.lerp(
                cameraRef.current.position.x,
                targetX,
                dampingFactor
            );
            cameraRef.current.position.z = THREE.MathUtils.lerp(
                cameraRef.current.position.z,
                targetZ,
                dampingFactor
            );
            cameraRef.current.lookAt(
                cameraRef.current.position.x,
                0,
                cameraRef.current.position.z
            );
        }

        // Add rotation for models based on mouse X
        const targetRotationZ = mouse.x * Math.PI; // Adjust rotation range as needed
        if (modelRef.current) {
            // Define target rotation based on mouse.x
            const targetRotationZ = mouse.x * Math.PI; // Same rotation range as before
            const targetQuaternion = new THREE.Quaternion();
            // Combine initial rotation with mouse-driven Y-axis rotation
            targetQuaternion.setFromEuler(
                new THREE.Euler(0, -Math.PI / 2 + targetRotationZ, Math.PI / 2, 'XYZ')
            );
            // Interpolate current quaternion to target quaternion
            modelRef.current.quaternion.slerp(targetQuaternion, dampingFactor);
        }
        imageMesh.rotation.z = THREE.MathUtils.lerp(
            imageMesh.rotation.z,
            targetRotationZ,
            dampingFactor
        );

        // Update directional light's x-position based on mouse.x
        const lightTargetX = initialLightX + mouse.x * lightMoveRange;
        directionalLight.position.x = THREE.MathUtils.lerp(
            directionalLight.position.x,
            lightTargetX,
            dampingFactor
        );

        renderer.render(scene, camera);
        requestAnimationFrame(tick);
    };
    tick();
4
  • I don't think that issue what you describe is gimbal lock... But could you make some codesandbox with model? Commented May 25 at 9:23
  • Thank you for responding. Sorry I am still quite new to codesandbox, and I tried to make a codesandbox but I am having some trouble reproducing my page (I think my folder management is not the best). However, I linked a view that illustrated my problem at the beginning of this post where it says " rotation issues". If the code preview is not of great importance, I can certainly provide a code sandbox with my complete code for that particular page. In the meantime I will read up how to provide an informative codesandbox code. Please let me know if the video or complete code will be helpful. Commented May 25 at 14:23
  • Could my issue be from the tick() function? Commented May 25 at 14:41
  • const targetRotationZ is defined twice in the same scope. thats probably killing your script midway Commented May 27 at 10:55

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.