Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Three.js - How to Pivot Camera around a Vector3 point?

Ok, I will try and be as concise as possible. I am not very good with math and what might seem obvious to you will most likely be rocket science to me.

I am using Three.js w/CSS3DRenderer to create a virtual gallery space.

I need a first person perspective, like an FPS game.

I have gotten the camera to move forwards, backwards, left and right all successfully.

However, when I go to rotate the camera, I get the result pictured here

The camera is rotating its local axis, but what I need is for the viewport, not the camera, to rotate, like

pictured here

So what I need is for the camera to orbit around a pivot point/vector, and then refocus by using Object3d.lookAt()

I am aware that I can solve my problem by parenting the camera as a child of another object, and then rotating the axis of the object. However, I would rather do the math myself.

In short, I want to understand how to rotate one vector point around another, and how to represent that relationship mathematically.

I do not want to utilize a script, e.g., three.js pointer_lock controls, to get the job done. I want to get my hands dirty with the actual math.

Any advice or links to tutorials would be much appreciated!!!

like image 373
pandakub Avatar asked May 22 '16 03:05

pandakub


2 Answers

Below is an example of a camera being rotated around a box.

It works by the fact that applying a rotation matrix always rotates an object around the origin. This is in contrast to just modifying the rotation property, which rotates the object around its own centre as you found out. The trick here is moving the camera 200 units away from the origin, such that when we apply the rotation matrix, it then rotates around the origin in a circle.

Since the box is at the origin, this will rotate the camera around the box. Then lookAt is used to point the camera towards the box.

Here is a low-level explanation on the subject if you're looking to learn more: http://webglfundamentals.org/webgl/lessons/webgl-scene-graph.html

var canvas = document.getElementById('canvas');
var scene = new THREE.Scene();
var renderer = new THREE.WebGLRenderer({canvas: canvas, antialias: true});
var camera = new THREE.PerspectiveCamera(45, canvas.clientWidth / canvas.clientWidth, 1, 1000);

var geometry = new THREE.BoxGeometry(50, 50, 50);
var material = new THREE.MeshBasicMaterial({color: '#f00'});
var box = new THREE.Mesh(geometry, material);
scene.add(box);

// important, otherwise the camera will spin on the spot.
camera.position.z = 200;

var period = 5; // rotation time in seconds
var clock = new THREE.Clock();
var matrix = new THREE.Matrix4(); // Pre-allocate empty matrix for performance. Don't want to make one of these every frame.
render();

function render() {
  requestAnimationFrame(render);
  if (canvas.width !== canvas.clientWidth || canvas.height !== canvas.clientHeight) {
    // This stuff in here is just for auto-resizing.
    renderer.setSize(canvas.clientWidth, canvas.clientHeight, false);
    camera.aspect = canvas.clientWidth /  canvas.clientHeight;
    camera.updateProjectionMatrix();
  }

  // Create a generic rotation matrix that will rotate an object
  // The math here just makes it rotate every 'period' seconds.
  matrix.makeRotationY(clock.getDelta() * 2 * Math.PI / period);

  // Apply matrix like this to rotate the camera.
  camera.position.applyMatrix4(matrix);

  // Make camera look at the box.
  camera.lookAt(box.position);

  // Render.
  renderer.render(scene, camera);
}
html, body, #canvas {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r77/three.js"></script>
<canvas id="canvas"></canvas>
like image 79
Brendan Annable Avatar answered Nov 09 '22 00:11

Brendan Annable


Standard method is to create var camera_pivot = new object3D() to the same location as the object. Put camera as a child, move camera back to make observable distance and rotate the object.

You can move object3D() and rotate by your needs. It is optimal solution for easy code and for performance.

On object3D you can use camera_pivot.translateX(), camera_pivot.rotateX(), camera_pivot.lookAt(obj) etc...

Other-way is difficult to do any actions without affect on another object in the scene.

like image 33
Martin Avatar answered Nov 08 '22 23:11

Martin