I'd argue the simplest way is to use a matrix hierarchy.
Make a node at the origin. Make a child node where you want the camera. Rotate the node at the origin. Ask the child where it is and put the camera there. Use lookAt
to orient the camera
This is pretty much ALWAYS easier than computing a circle. You can achieve all kinds of effects by creatively putting nodes in a scene, moving them around and using them set both the position and the target for a camera.
var canvas = document.querySelector("#c");
var camera = new THREE.PerspectiveCamera(70, 1, 1, 1000);
var scene = new THREE.Scene();
// make some cubes
var geometry = new THREE.BoxBufferGeometry(20, 20, 20);
var material = new THREE.MeshLambertMaterial({ color: 0xFFEECC });
for (var z = -1; z <= 1; ++z) {
for (var x = -1; x <= 1; ++x) {
var mesh = new THREE.Mesh(geometry, material);
mesh.position.x = x * 30;
mesh.position.z = z * 30;
scene.add(mesh);
}
}
// add some lights
var light = new THREE.DirectionalLight(0xE0E0FF, 1);
light.position.set(200, 500, 200);
scene.add(light);
var light = new THREE.DirectionalLight(0xFFE0E0, 0.95);
light.position.set(-200, -500, -200);
scene.add(light);
// now make nodes for camera
var cameraCenterNode = new THREE.Object3D();
var cameraPositionNode = new THREE.Object3D();
scene.add(cameraCenterNode);
cameraCenterNode.add(cameraPositionNode);
cameraPositionNode.position.x = 100;
cameraPositionNode.position.y = 40;
var renderer = new THREE.WebGLRenderer({canvas: canvas});
function resizeIfChanged() {
var width = canvas.clientWidth;
var height = canvas.clientHeight;
if (canvas.width != width || canvas.height != height) {
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize(width, height, false);
}
}
function render(time) {
time *= 0.001; // make it seconds
resizeIfChanged();
// Rotate camera center
cameraCenterNode.rotation.y = time;
// get cameraPositionNode's world position and put it in camera
cameraPositionNode.getWorldPosition(camera.position);
// point camera at center
camera.lookAt(cameraCenterNode.position);
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
body { margin: 0 }
canvas { width: 100vw; height: 100vh; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r78/three.min.js"></script>
<canvas id="c"></canvas>
As for zooming it really depends on what you want to achieve.
For example, you could compute a point between cameraCenterNode
and cameraPositionNode
. Example:
var out = cameraPositionNode.getWorldPosition();
var in = cameraCenternode.getWorldPosition();
in.lerp(out, zoomAmount); // where 0.0 = in and 1.0 = out
// now set the camera there
camera.position.copy(in);
Or can always just move the camera forward along its -zAxis
var worldMatrix = camera.getWorldMatrix();
var zoomVector = new THREE.Vector3(
wm.elememts[8], wm.elememts[9], wm.elememts[10]);
camera.position.sub(zoomVector.multiplyScalar(zoomAmount));
It's not clear from your question how you really want the camera to work. If you always want it to point to the origin and always rotate around OR if you want it more free floating like a typical modeling package. Regardless though you have to pick some point to rotate around. Whether it's a fixed point or a new point depending on where the camera is the same type of calculations will work.