kpie
kpie

Reputation: 11080

Three.js Trackball zoom works rotation does not

The title pretty much says it all. I expect trackerballcontrols to behave like this example but for some reason I cannot rotate the camera only zoom in and out. Ovbiously I would like to be able to rotate the camera. Here's the code.

        <!DOCTYPE html>
        <html>
        <head>
        <title>Page Title</title>
        </head>
        <body>
        
        <h1>FooBarBaz</h1>
        <p>LaDeDa</p>
        <script src="http://threejs.org/build/three.min.js"></script>
        <script src="https://threejs.org/examples/js/controls/TrackballControls.js"></script>
        <script>
        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
        
        var renderer = new THREE.WebGLRenderer();
        renderer.setSize( window.innerWidth, window.innerHeight );
        
        var objects = [
            {
                name : "earth",
                mesh : new THREE.Mesh(new THREE.SphereGeometry(1, 32, 32), new THREE.MeshPhongMaterial()),
                init : function(scene){
                this.mesh.position.set(0,0,0);
                //this.material.map = THREE.ImageUtils.loadTexture('../earth.jpg');
                scene.add(this.mesh);
                },
                animate : function(t){return}
            },
            {
                name : "satellite",
                mesh : new THREE.Mesh(new THREE.SphereGeometry(0.1, 32, 32), new THREE.MeshPhongMaterial()),
                init : function(scene){
                this.mesh.position.set(1.5,0,0);
                //this.material.map = THREE.ImageUtils.loadTexture('../earth.jpg');
                scene.add(this.mesh);
                },
                animate : function(t){this.mesh.position.set(Math.sin(t)*1.5,Math.cos(t)*1.5,0);}
            }];
        objects.forEach(object => object.init(scene));
        
        var light = new THREE.HemisphereLight(0xf6e86d, 0x404040, 0.5);
        scene.add(light);
        
        camera.position.x = 0;
        camera.position.y = -5;
        camera.position.z = 0;
        camera.lookAt(new THREE.Vector3( 0, 0, 0));
        var timeStep = 0.01;
        var time = 0;
        var controls = new THREE.TrackballControls( camera, renderer.domElement );
        controls.target.set( 0, 0, 0 );
        var render = function () {
            time += timeStep;
            requestAnimationFrame( render );
            objects.forEach(object => object.animate(time));
            controls.update();
            renderer.render(scene, camera);
        }            
        document.body.appendChild( renderer.domElement );
        render();</script>
        </body>
        </html>
        

Upvotes: 0

Views: 540

Answers (1)

Clark Kent
Clark Kent

Reputation: 36

There are two points in your code need adjustment.

  1. You need to append renderer.domElement to body before initializing controls:

    document.body.appendChild(renderer.domElement);

    var controls = new THREE.TrackballControls(camera, renderer.domElement);

  2. Since you make your camera.position on y-axis, and in TrackballControls camera.up is default set to y-axis, this makes your controls unable to work porperly. So what you need to do is to change the default camera.up behaviour:

    camera.up = new THREE.Vector3(1, 1, 1);//you can change the values freely ,just dont make it parallel to y-axis

    Sorry I'm not a ThreeJS expert, you can refer to this for more information:https://github.com/mrdoob/three.js/issues/10161

So the code below works fine:

<!DOCTYPE html>
<html>

<head>
<title>Page Title</title>
</head>

<body>
<h1>FooBarBaz</h1>
<p>LaDeDa</p>
<script src="http://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/TrackballControls.js"></script>
<script>
    var scene = new THREE.Scene();
    var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

    var renderer = new THREE.WebGLRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);


    var objects = [
        {
            name: "earth",
            mesh: new THREE.Mesh(new THREE.SphereGeometry(1, 32, 32), new THREE.MeshPhongMaterial()),
            init: function (scene) {
                this.mesh.position.set(0, 0, 0);
                //this.material.map = THREE.ImageUtils.loadTexture('../earth.jpg');
                scene.add(this.mesh);
            },
            animate: function (t) { return }
        },
        {
            name: "satellite",
            mesh: new THREE.Mesh(new THREE.SphereGeometry(0.1, 32, 32), new THREE.MeshPhongMaterial()),
            init: function (scene) {
                this.mesh.position.set(1.5, 0, 0);
                //this.material.map = THREE.ImageUtils.loadTexture('../earth.jpg');
                scene.add(this.mesh);
            },
            animate: function (t) { this.mesh.position.set(Math.sin(t) * 1.5, Math.cos(t) * 1.5, 0); }
        }];
    objects.forEach(object => object.init(scene));

    var light = new THREE.HemisphereLight(0xf6e86d, 0x404040, 0.5);
    scene.add(light);

    camera.position.x = 0;
    camera.position.y = -5;
    camera.position.z = 0;
    camera.up = new THREE.Vector3(1, 1, 1);

    camera.lookAt(new THREE.Vector3(0, 0, 0));
    var timeStep = 0.01;
    var time = 0;

    document.body.appendChild(renderer.domElement);
    var controls = new THREE.TrackballControls(camera, renderer.domElement);
    controls.target.set(0, 0, 0);
    var render = function () {
        time += timeStep;
        requestAnimationFrame(render);
        objects.forEach(object => object.animate(time));
        controls.update();
        renderer.render(scene, camera);
    }

    render();</script>
</body>

</html>

Upvotes: 2

Related Questions