Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ThreeJS - OrbitControl with different rotate center and lookAt point

Tags:

three.js

I have been using OrbitControl in my app to allow rotating camera around the world. Recently I am trying to enhance the control to allow the camera to rotate around an arbitrary point, not just the camera lookAt point. I have not had much success yet.

In the code if I remove this: this.object.lookAt( this.target ); it did not work well. Any ideas?

Some pictures to clarify: enter image description here enter image description here

I rotated the camera around the center of the object (pivot), but the camera is not looking at the center.

like image 915
ChrisU Avatar asked Dec 30 '15 09:12

ChrisU


2 Answers

Just update the controls.target property, for example:

controls.target.set(1, 5, 7);

or target a mesh:

controls.target.copy(mesh.position)
like image 196
Brendan Annable Avatar answered Nov 13 '22 19:11

Brendan Annable


OrbitControls were designed for orbiting a scene, with the camera viewport looking directly at the controls rotation target. They are not designed to handle objects rotation separate from camera, they have TransformControls but those don't support damping.

Rotating with Orbit controls, locks your camera viewport to look at the center (the dotted line), and rotates around the center (the red line):

enter image description here

If you move/pan the target, both camera target and rotation center are moving together like this:

enter image description here

What you need is the rotation center and the camera target to be independent, so the camera rotates around the object, whilst looking at a certain point like this:

enter image description here

There seem to be two approaches to creating custom camera/rotation functionality:

1) Modify OrbitControls Change the camera.lookAt to be offset from controls.target

View changes needed to OrbitControls: https://github.com/sciecode/three.js/commit/dccf1578343bb9b7c79bb2eb2004d5ee34a76e6a#diff-ffef32863dd826c87a45cfb28c4ddd83

Demo of custom Orbit Controls: https://jsfiddle.net/kmturley/6qxh3zc9/28/

2) Modify TransformControls Change transform controls to allow damping, free spinning, and hide the gizmo overlays.

Demo of custom Transform Controls https://jsfiddle.net/kmturley/2p1v6bcw/18/

3) Create your own Object rotation controls

import * as THREE from "https://threejs.org/build/three.module.js";

var mesh, renderer, scene, camera, controls;
var radius = 5;
var group;
var targetRotationX = 0;
var targetRotationOnMouseDownX = 0;
var targetRotationY = 0;
var targetRotationOnMouseDownY = 0;
var mouseX = 0;
var mouseXOnMouseDown = 0;
var mouseY = 0;
var mouseYOnMouseDown = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
var finalRotationY

init();
animate();

function init() {

  // renderer
  renderer = new THREE.WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.setPixelRatio(window.devicePixelRatio);
  document.body.appendChild(renderer.domElement);

  // scene
  scene = new THREE.Scene();

  // camera
  camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 10000);
  camera.position.set(0, radius * 2, radius * 2);
  camera.lookAt(0, radius, 0)

  // controls
  /*     controls = new OrbitControls( camera, renderer.domElement ); */
  document.addEventListener('mousedown', onDocumentMouseDown, false);
  document.addEventListener('touchstart', onDocumentTouchStart, false);
  document.addEventListener('touchmove', onDocumentTouchMove, false);

  // ambient
  scene.add(new THREE.AmbientLight(0x222222));

  // light
  var light = new THREE.DirectionalLight(0xffffff, 1);
  light.position.set(20, 20, 0);
  scene.add(light);

  // geometry
  var geometry = new THREE.SphereGeometry(radius, 12, 8);

  // material
  var material = new THREE.MeshPhongMaterial({
    color: 0x00ffff,
    flatShading: true,
    transparent: true,
    opacity: 0.7,
  });

  // mesh
  group = new THREE.Object3D();
  mesh = new THREE.Mesh(geometry, material);
  group.add(mesh);
  scene.add(group);
}

function onDocumentMouseDown(event) {
  event.preventDefault();
  document.addEventListener('mousemove', onDocumentMouseMove, false);
  document.addEventListener('mouseup', onDocumentMouseUp, false);
  document.addEventListener('mouseout', onDocumentMouseOut, false);
  mouseXOnMouseDown = event.clientX - windowHalfX;
  targetRotationOnMouseDownX = targetRotationX;
  mouseYOnMouseDown = event.clientY - windowHalfY;
  targetRotationOnMouseDownY = targetRotationY;
}

function onDocumentMouseMove(event) {
  mouseX = event.clientX - windowHalfX;
  mouseY = event.clientY - windowHalfY;
  targetRotationY = targetRotationOnMouseDownY + (mouseY - mouseYOnMouseDown) * 0.02;
  targetRotationX = targetRotationOnMouseDownX + (mouseX - mouseXOnMouseDown) * 0.02;
}

function onDocumentMouseUp(event) {
  document.removeEventListener('mousemove', onDocumentMouseMove, false);
  document.removeEventListener('mouseup', onDocumentMouseUp, false);
  document.removeEventListener('mouseout', onDocumentMouseOut, false);
}

function onDocumentMouseOut(event) {
  document.removeEventListener('mousemove', onDocumentMouseMove, false);
  document.removeEventListener('mouseup', onDocumentMouseUp, false);
  document.removeEventListener('mouseout', onDocumentMouseOut, false);
}

function onDocumentTouchStart(event) {
  if (event.touches.length == 1) {
    event.preventDefault();
    mouseXOnMouseDown = event.touches[0].pageX - windowHalfX;
    targetRotationOnMouseDownX = targetRotationX;
    mouseYOnMouseDown = event.touches[0].pageY - windowHalfY;
    targetRotationOnMouseDownY = targetRotationY;
  }
}

function onDocumentTouchMove(event) {
  if (event.touches.length == 1) {
    event.preventDefault();
    mouseX = event.touches[0].pageX - windowHalfX;
    targetRotationX = targetRotationOnMouseDownX + (mouseX - mouseXOnMouseDown) * 0.05;
    mouseY = event.touches[0].pageY - windowHalfY;
    targetRotationY = targetRotationOnMouseDownY + (mouseY - mouseYOnMouseDown) * 0.05;
  }
}

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

function rotate() {
  group.rotation.y += (targetRotationX - group.rotation.y) * 0.1;
  finalRotationY = (targetRotationY - group.rotation.x);
  if (group.rotation.x <= 1 && group.rotation.x >= -1) {
    group.rotation.x += finalRotationY * 0.1;
  }
  if (group.rotation.x > 1) {
    group.rotation.x = 1
  }
  if (group.rotation.x < -1) {
    group.rotation.x = -1
  }
}

Demo of custom rotation controls: https://jsfiddle.net/kmturley/6317jd95/11/

Another person's example: http://projects.defmech.com/ThreeJSObjectRotationWithQuaternion/

There is a discussion of these approaches in the three.js github project: https://github.com/mrdoob/three.js/issues/18476

like image 35
Kim T Avatar answered Nov 13 '22 20:11

Kim T