I have an object that moves and rotates, and I want the camera to stay a certain distance behind it. To be clear, I'm drawing an airplane and want the camera to always be looking at its rear. (Unless the user drags the mouse, for example to look at the top of the airplane as it flies).
So say I have set the position and rotation of the airplane (instance of THREE.Object3D):
airplane.position = {x: 1, y:2, z: 3};
airplane.rotation = {x: Math.PI/4, y:1.2, z: 0};
And say, when the rotation and positions are (0,0,0) the camera is at (5, 0, 0), (i.e. 5 units behind the airplane's center), what would be the simplest way of finding the position vector to set the camera at?
Thanks
Sorry for the sprawled code, I'm hacking it to death. I'd make a jsfiddle for it, but haven't got a server to host three.js on...
$(function(){
var camera1, camera2, scene, renderer, viewPort;
var objectManager;
var views = [];
var vpWidth, vpHeight;
init();
animate();
updateSize();
function updateSize(){
vpWidth = viewPort.innerWidth();
vpHeight = viewPort.innerHeight();
}
function init() {
viewPort = $('#viewPort');
objectManager = new ObjectManager();
views[0] = new View(viewPort, objectManager);
var view = views[0];
view.fov = 20;
view.proportions.height = 0.5;
view.proportions.bottom = 0.5;
view.init();
views[1] = new View(viewPort, objectManager);
var view = views[1];
view.fov = 10;
view.proportions.height = 0.5;
view.init();
view.updateCamera = function(){
//-----------------------------------------------------
// when the user drags the mouse, (not yet implemented)
// the following camera position numbers would change
// so that he could view for example the top of the
// airplane as it flies
//-----------------------------------------------------
this.camera.position.set( 5,5,5 );
//-----------------------------------------------------
// This line does not work as expected: the airplane
// does not stay in the center of the view but follows
// some sort of curved path with respect to the camera
//-----------------------------------------------------
this.camera.lookAt(objectManager.airplane.position);
this.camera.updateProjectionMatrix();
};
scene = new THREE.Scene();
objectManager.addTo(scene);
objectManager.airplane.add(views[1].camera);
//-----------------------------------------------
// The following two lines *do* work correctly //
//-----------------------------------------------
views[1].camera.position.set( 0,0,5 );
views[1].camera.lookAt(objectManager.airplane.position);
var ambientLight = new THREE.AmbientLight(0x808080);
scene.add(ambientLight);
var pointLight = new THREE.PointLight(0x808080);
pointLight.position = {x: 100, y: 100, z: 100};
scene.add(pointLight);
renderer = new THREE.WebGLRenderer();
renderer.setClearColorHex(0x000000, 1);
renderer.setSize( viewPort.innerWidth(), viewPort.innerHeight() );
viewPort.get(0).appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
objectManager.tick();
var view;
for (var i in views){
view = views[i];
view.updateCamera();
pixels = view.pixels;
renderer.setViewport(pixels.left, pixels.bottom, pixels.width, pixels.height);
renderer.setScissor(pixels.left, pixels.bottom, pixels.width, pixels.height);
renderer.enableScissorTest(true);
renderer.render( scene, view.camera );
}
}
});
function View(vp, om){
this.objectManager = om;
this.viewPort = vp;
this.fov = 30;
this.proportions = { left: 0, bottom: 0, height: 1, width: 1 };
this.pixels = { left: 0, bottom: 0, height: 0, width: 0, aspect: 0 };
this.aspect;
this.init = function(){
this.camera = new THREE.PerspectiveCamera(
this.fov,
this.viewPort.innerWidth() / this.viewPort.innerHeight(),
0.1, 10000
);
this.pixels.left = Math.floor(this.proportions.left * this.viewPort.innerWidth());
this.pixels.width = Math.floor(this.proportions.width * this.viewPort.innerWidth());
this.pixels.bottom = Math.floor(this.proportions.bottom * this.viewPort.innerHeight());
this.pixels.height = Math.floor(this.proportions.height * this.viewPort.innerHeight());
this.pixels.aspect = this.pixels.width / this.pixels.height;
this.camera.position.y = 0;
this.camera.position.z = 10;
this.camera.aspect = this.pixels.aspect;
this.camera.updateProjectionMatrix();
};
this.updateCamera = function(){};
}
function newCube(dims, pos, cols, colAss){
var mesh;
var geometry;
var materials = [];
geometry = new THREE.CubeGeometry( dims.x, dims.y, dims.z );
for (var i in cols){
materials[i] = new THREE.MeshLambertMaterial( { color: cols[i], ambient: cols[i], overdraw: true } );
}
geometry.materials = materials;
for (var i in colAss){
geometry.faces[i].materialIndex = colAss[i];
}
mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( materials ) );
mesh.position = pos;
return mesh;
}
function ObjectManager(){
this.airplane;
var fuselage;
var tail;
var grid;
this.addTo = function(scene){
this.airplane = new THREE.Object3D();
fuselage = newCube(
{x: 1, y: 0.1, z: 0.1},
{x: 0, y: 0, z: 0},
[0xffff00, 0x808000, 0x0000ff, 0xff00000, 0xffffff, 0x808080],
[0, 1, 2, 3, 4, 5]
);
this.airplane.add(fuselage);
tail = newCube(
{x: 0.15, y: 0.2, z: 0.05},
{x: 0.5, y: 0.199, z: 0},
[0xffff00, 0x808000, 0x0000ff, 0xff00000, 0xffffff, 0x808080],
[0, 1, 2, 3, 4, 5]
);
this.airplane.add(tail);
scene.add( this.airplane );
grid = new THREE.Object3D();
var geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3( - 200, 0, 0 ) );
geometry.vertices.push(new THREE.Vector3( 200, 0, 0 ) );
linesMaterial = new THREE.LineBasicMaterial( { color: 0x00ff00, opacity: 1, linewidth: .1 } );
for ( var i = 0; i <= 200; i ++ ) {
var line = new THREE.Line( geometry, linesMaterial );
line.position.z = ( i * 2 ) - 200;
grid.add( line );
var line = new THREE.Line( geometry, linesMaterial );
line.position.x = ( i * 2 ) - 200;
line.rotation.y = 90 * Math.PI / 180;
grid.add( line );
}
scene.add( grid );
};
this.tick = function(){
this.airplane.rotation.x += 0.005;
this.airplane.rotation.y += 0.01;
this.airplane.position.x += 0.01;
};
};