19

I'm displaying an OBJ element with Three.js using WebGlRenderer, now I'd like to allow users to rotate the camera around the object in any direction, I've found this answer:

Rotate camera in Three.js with mouse

But both examples return me errors, the first says that projector is not defined, and I don't know what it means with "projector". I've just a simple camera, the object and some light. The second code says that undefined is not a function.

Does someone know how to get the result I need?

7 Answers 7

37

This is what you want: http://threejs.org/examples/misc_controls_orbit.html

Include the orbit controls (after you have downloaded them):

<script src="js/controls/OrbitControls.js"></script>

Setup the variable:

var controls;

Attach the controls to the camera and add a listener:

controls = new THREE.OrbitControls( camera );
controls.addEventListener( 'change', render );

and in your animate function update the controls:

controls.update();

[Update] controls.autoRotate = true; (tested in v73. Recent versions of OrbitControls.js has added this control.)

Sign up to request clarification or add additional context in comments.

9 Comments

Thank you but now is the item that rotates around the camera... how can I invert the behavior? thanks
@FezVrasta You can choose what to orbit so instead of camera you can put an object in there if you like for example "sphere" so it would be: new THREE.OrbitControls( sphere );
Thanks but I can't make it works, I use this code to load the OBJ: jsfiddle.net/7aqmB but if I use object in OrbitControls it says that object is undefined...
It's not necessary to write controls.addEventListener( 'change', render ); in the code. The library is doing it itself. And controls.update() must be inside the function render(){...}, NOT in the function animate(){...}
... even is not necessary to use controls.update() in render(). It will work.
|
5

If you don't want to mess with OrbitControls, simply add the camera to a boom Group

  const boom = new THREE.Group();
  boom.add(camera);
  scene.add(boom);
  camera.position.set( 0, 0, 100 ); // this sets the boom's length 
  camera.lookAt( 0, 0, 0 ); // camera looks at the boom's zero

then you can rotate this boom instead of the camera itself.

  boom.rotation.x += 0.01;

You may want to add some extra objects, like lights etc. to this boom, btw

Comments

2

Here is a quick hack, in case you don't want to use the OrbitControls for some reason.

            camera.position.copy( target );
            camera.position.x+=Math.sin(camera.rotationy)*3;
            camera.position.z+=Math.cos(camera.rotationy)*3;
            camera.position.y+=cameraHeight; // optional
            tempVector.copy(target).y+=cameraHeight; // the += is optional
            camera.lookAt( tempVector );

camera.rotationy is a copy of the mouse rotation value since we are changing it with the call to lookAt.

Comments

1

Indeed, if you substitute 'camera' with the object of your choice, the object will rotate. But if there are other objects surrounding it (for example a grid on the floor), they will still stand still. That might be what you want, or it might look weird. (Imagine a chair rotating floating above the floor...?)

I choose to override the center object from OrbitControls.JS from my code after initializing the Orbit Controls

controls = new THREE.OrbitControls(camera, renderer.domElement);
…
controls.center =  new THREE.Vector3(
    chair.position.x,
    chair.position.y,
    chair.position.z
);

(disclaimer: I have the impression there are different versions of OrbitControls.js around, but I assume they all use this center-object)

Comments

1

If you are using ES6, following could be used for OrbitControls

import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';

// this would create the orbit controls
// it would allow camera control using mouse
const orbitControls = new OrbitControls(camera, renderer.domElement);

If you need autorotate,

function init() {
  ...

  // following would enable autorotate
  const orbitControls.autoRotate = true;

  ..
}

function animate() {
  // need to update the orbitcontrols for autorotate camera to take effect
  orbitControls.update();

  ...
  renderer.render( scene, camera );
  requestAnimationFrame( animate );
}

For ref: https://threejs.org/docs/#examples/en/controls/OrbitControls

Comments

0

Add a listener to trigger render method on change of OrbitControl:

    const controls = new OrbitControls(camera, this.renderer.domElement);
    controls.enableDamping = true;   //damping 
    controls.dampingFactor = 0.25;   //damping inertia
    controls.enableZoom = true;      //Zooming
    controls.autoRotate = true;       // enable rotation
    controls.maxPolarAngle = Math.PI / 2; // Limit angle of visibility

   controls.addEventListener("change", () => {
      if (this.renderer) this.renderer.render(this.scene, camera);
    });

and in animate update controls:

  start = () => {
    if (!this.frameId) {
      this.frameId = requestAnimationFrame(this.animate);
    }
  };
  stop = () => {
    cancelAnimationFrame(this.frameId);
  };

  renderScene = () => {
    if (this.renderer) this.renderer.render(this.scene, camera);
  };


animate = () => {
    // update controls
    controls.update();
}

Comments

0

Extra info for who looking auto rotate direction change on a limit:

if (
   controls.getAzimuthalAngle() >= Math.PI / 2 ||
   controls.getAzimuthalAngle() <= -Math.PI / 2
 ) {
   controls.autoRotateSpeed *= -1;
 }

 controls.update();

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.