How to rotate a gltf model using mouse events?

I have a gltf model in my scene that I want to rotate using a mouse event (or touch event) each time the mouse is down. But I getting this error Uncaught Reference Error: model is not defined every time I run my code:

 <script src="js/three.js"></script>
<script src="js/GLTFLoader.js"></script>
<script>
    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

    const light = new THREE.DirectionalLight(0x3C00FA, 2)
    light.position.set(3, 5, 5)
    scene.add(light)

    const renderer = new THREE.WebGLRenderer({
        antialias: true
    })
    renderer.setSize( window.innerWidth, window.innerHeight );
    renderer.setPixelRatio(window.devicePixelRatio)
    document.body.appendChild( renderer.domElement );

    camera.position.z = 1000;

    function animate() {
        requestAnimationFrame( animate );
        renderer.render( scene, camera );
    }
    animate();
    
    // Instantiate a loader
 const loader = new THREE.GLTFLoader();

    loader.load( 'models/virus.gltf', function ( gltf ) {
        const model = gltf.scene;
        scene.add(model);

        gltf.rotateX(0.5)

        },
        // called while loading is progressing
        function ( xhr ) {

            console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );

        },
        // called when loading has errors
        function ( error ) {

            console.log( 'An error happened' );

        }
        
    );

    document.addEventListener(`mousedown`, function () {
        if (model) {
            model.rotation.x += 0.01;
        }
    })
    
    
</script>

Try to define the model variable at the top of your file and not inside the onLoad() callback. In this way, it should be accessible if you try to animate it in your mousedown event listener.

<script src="js/three.js"></script>
<script src="js/GLTFLoader.js"></script>
<script>
    let model;
    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

    const light = new THREE.DirectionalLight(0x3C00FA, 2)
    light.position.set(3, 5, 5)
    scene.add(light)

    const renderer = new THREE.WebGLRenderer({
        antialias: true
    })
    renderer.setSize( window.innerWidth, window.innerHeight );
    renderer.setPixelRatio(window.devicePixelRatio)
    document.body.appendChild( renderer.domElement );

    camera.position.z = 1000;

    function animate() {
        requestAnimationFrame( animate );
        renderer.render( scene, camera );
    }
    animate();
    
    // Instantiate a loader
 const loader = new THREE.GLTFLoader();

    loader.load( 'models/virus.gltf', function ( gltf ) {
        model = gltf.scene;
        scene.add(model);

        gltf.rotateX(0.5);

        },
        // called while loading is progressing
        function ( xhr ) {

            console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );

        },
        // called when loading has errors
        function ( error ) {

            console.log( 'An error happened' );

        }
        
    );

    document.addEventListener(`mousedown`, function () {
        if (model) {
            model.rotation.x += 0.01;
        }
    })
    
    
</script>
1 Like

Yeah perfect! It works.

Why at the top and not inside the onLoad() callback?

It’s a matter of variable scope. If you define model inside the callback, it is only visible in this block. Putting it at the top of your file will make the variable globally visible.

1 Like

Make sense. Thx.