ThreeJS: move the camera to specific coordinates using tween.js - onClick

1k views Asked by At

I am having an issue combining Tween.js and ThreeJS to animate and move the camera. I include both of them into my reactJS boilerplate.

What I want: I want to click on an object and the camera should then move to predefined coordinates smoothly. But I can't get it to work and cannot find any documentation on how to do this. All code snippets I found so far fail or lack on documentation. This is my code:

const THREE = require('three');
const TWEEN = require('tween.js');
const OrbitControls = require('three-orbit-controls')(THREE);

var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
var cameraPosition = new THREE.Vector3();
var objects = [];

export default class App {

    constructor () {
        this.alive = true;
        this.init();
    }

    init () {
        this.scene = new THREE.Scene();
        this.camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, .1, 1000);
        this.renderer = new THREE.WebGLRenderer( { antialias: true } );
        this.renderer.setSize( window.innerWidth, window.innerHeight );
        document.body.prepend( this.renderer.domElement );
        window.addEventListener("mousedown", this.onclick, true);
        requestAnimationFrame(this.update);

        this.test();
        this.start();
    }

    onclick(e) {
        new TWEEN.Tween( cameraPosition )
          .to( {
            x: 20,
            y: 20,
            z: 20}, 2000 )
          .easing( TWEEN.Easing.Sinusoidal.EaseInOut)
          .start();
    }

    test () {
        this.displayA= new ModelLoader();
        this.displayA.loadModel('./models/display-A.obj', (obj) => {
            obj.scale.set(.5, .5, .5);
            obj.position.z = 0;
            obj.position.y = 5;
            obj.position.x = 0;
            obj.rotation.x = this.deg2rad(-90);
            obj.rotation.y = this.deg2rad(0);
            obj.rotation.z = this.deg2rad(90);
            obj.name = "Display";
            console.log(obj.name);
            this.object = new THREE.Group();
            this.object.add(obj);
            this.scene.add(this.object);
            this.object.name = "Display";
            objects.push(this.object);
        });
    }

    render () {

        this.update();
        this.renderer.render( this.scene, this.camera );
        requestAnimationFrame(this.render.bind(this));

    }

    update () {
        this.camera.position.copy(cameraPosition);
    }

First of all, the camera does not move, as I get "'this' is not defined." pointing to the line inside the "update()" function. And second the click does not work, too. The error message here is "camera is not defined".

Would be amazing if someone can help me with this.

Thanks :)

1

There are 1 answers

0
danlong On

Your requestAnimationFrame call should run your render() method, not the update() method. The update() method is then called inside of the render() method.

Although, I see this.start() called but no reference to that method, so not sure what that does?

I would add an animate() method to handle update() and render(), which is called on requestAnimationFrame().

E.g:

animate() {
    requestAnimationFrame( this.animate );
    this.update();
    this.render();
}

Render() would become:

render () {
    TWEEN.update();
    this.renderer.render( this.scene, this.camera );
}

Then, inside init(), where you currently have requestAnimationFrame(this.update); - replace with this.animate();

You might need to update the eventListener reference to:

window.addEventListener("mousedown", e => this.onclick(e), true);

This should fix the scoping problems you're having. The Tween.js looks OK, but without a demo, I can't say for sure and the references to this.start(), which isn't in the code snippet so cannot account for that.

There's also no reason why the Tween method couldn't update the this.camera.position object values instead of the 'cameraPosition' Vector3, depending on what else you want to run in your project.