How to make the camera rotate around a moving object and follow the object?

const mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshBasicMaterial({ color: 0xffff00 }));
const rotatemat = new THREE.Matrix4()
const translationmat = new THREE.Matrix4()
const dir = new THREE.Vector3().subVectors(camera.position.clone(), mesh.position.clone())

renderer.setAnimationLoop(() => {
   translatemat.makeTranslation(num, -num, 0)
   mesh.position.applyMatrix4(translatemat)
   rotatemat.makeRotationAxis(camera.getWorldDirection(mesh.up).normalize(), p)
   const camp = new THREE.Vector3().addVectors(mesh.position.clone(), dir.clone())
   camp.applyMatrix4(rotatemat)
   camera.position.copy(camp)
   camera.lookAt(mesh.position)
})

I calculate the direction vector between the camera coordinates and the object coordinates, move the object and update the camera position, but the camera does not rotate around the up axis of the object. I don’t know what the problem is?

It seems that there is something wrong with my rotation axis. How can I calculate the rotation axis of the camera around the object

1 Like

Maybe you can use this approach: Edit fiddle - JSFiddle - Code Playground

The camera is a child of the mesh. The mesh circles around the origin whereas the camera circles around the mesh and focuses it.

1 Like

Thank you very much for your reply, but this address cannot be accessed :grinning:

Thank you for your reminder. I don’t know whether this is the right way to write, but it does achieve the effect I want.

mesh.add(camera)
renderer.setAnimationLoop(() => {
   translatemat.makeTranslation(num, -num, 0)
   mesh.position.applyMatrix4(translatemat)
   rotatemat.makeRotationY(num)
   camera.applyMatrix4(rotatemat)
   camera.lookAt(mesh.position)
})

Here is the code:

let camera, scene, renderer;
let clock, mesh;

init();
animate();

function init() {

    camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 20 );
    camera.position.set( 0, 4, 4 );

    scene = new THREE.Scene();
    
    clock = new THREE.Clock();

    const geometry = new THREE.BoxGeometry();
    const material = new THREE.MeshNormalMaterial();

    mesh = new THREE.Mesh( geometry, material );
    scene.add( mesh );
    
    scene.add( new THREE.GridHelper() );
    
    mesh.add( camera );

    renderer = new THREE.WebGLRenderer( { antialias: true } );
    renderer.setSize( window.innerWidth, window.innerHeight );
    document.body.appendChild( renderer.domElement );

}

function animate() {

    requestAnimationFrame( animate );
    
    const time = clock.getElapsedTime();
    
    mesh.position.x = Math.sin( time ) * 2;
    mesh.position.z = Math.cos( time ) * 2;
    
    camera.position.x = Math.sin( time ) * 2;
    camera.position.z = Math.cos( time ) * 2;
    
    camera.lookAt( mesh.position );
    
    renderer.render( scene, camera );

}
1 Like

Sounds like you’re going for a third person camera, this tutorial describes implementing it pretty well.

1 Like

@Mugen87 Thank you very much for sharing. :smiling_face_with_three_hearts:

Thank you for sharing, but I can’t visit YouTube to view this tutorial.Is there any other way to view this tutorial? :thinking:

Can’t you use a VPN? There are plugins for common browsers so you don’t need a separate software.

Oh wait, you are from China, right? Forget what I said about VPNs :innocent: .

Unfortunately I don’t think this tutorial is available on other sites. But here’s the github repo with the code from the video, hopefully you can access that :slight_smile:

One of my favorite topics!

Here is a completely different approach that I use to accomplish the same thing.
I link the camera to a 3D object, which acts like a “selfie stick”.
I then link the 3D object to the 3D object of interest so that it is holding the stick
I use mouse input to orbit the camera around the object of interest:

  • mouseX = longitude
  • mouseY = latitude.

Here is some sample code:

// Camera Variables
let CamDst = 500;	// distance from object you are looking at
let CamLat = 30;	// vertical position of camera (+/-90 degrees) 30 = up
let CamLon = 0;		// horizontal position of camera (0-360 degrees) 0 = straight ahead
let LatMax = 90;	// limit input value to 90 degrees, so you don't go "upside down"
let LatMin = -90;	// Same for down	
// Create Camera and Holder
const camera = new THREE.PerspectiveCamera(45, width/height, 1, 15000);
	camera.rotation.order = "YXZ";
const camobj = new THREE.Object3D();	// This is like a camera "selfie stick" that holds the camera
	camobj.rotation.order = "YXZ";	// You rotate the "stick" to position the camera in space
	camobj.add(camera);		// Attach the camera to the stick
	camera.position.z = -CamDst;	// Length of "stick"
	camera.rotation.y = 180*DegRad;	// Camera looks towards the object holding the "stick"
// Object of Interest (you can add the mesh later)
const ctrobj = new THREE.Object3D();	// Create object
	ctrobj.rotation.order = "YXZ";
	ctrobj.add(camobj);		// Attach camera "stick" to the object
	scene.add(ctrobj);

// I use mouse input to rotate the lat/lon of the "stick", which causes the camera to orbit the object:
// * up/down changes latitude (limit to +/-90 degrees)
// * left/right changes longitude
// * mouse wheel changes distance from object
// I call the function below with each frame (but it is so small, you can just include it in your code)
function moveCamera() {
	camera.position.z = -CamDst;	// in case, change distance from object
	camobj.rotation.x = Mod360(CamLat)*DegRad;
	camobj.rotation.y = Mod360(CamLon+180)*DegRad;
}

Note: that you can also “bank” the camera using rotation.z - something you can’t do with LookAt
Also, note: I am using 3Dobjects, rather than just a mesh because you can link to a 3Dobject.

This is a pretty flexible setup:

  1. You can easily look outwards (just make camera.roation.y = 0)
  2. You can attach the camera holder to different objects of interest (e.g. different planets rotating the sun) to look at them.
  3. You can use linked objects to change the orientation of your axis.

Great sharing. I achieved the expected results through this sharing. Thank you very much :laughing:

After reading the code provided by you, the content of the code is to store the object to be linked in one object3d and the camera in another object3d, then add the camera’s object3d to the obejct3d where the linked object is stored, and change the rotation of the camera through the mouse mouseover event. What I need to change is the position and orientation of the object. I think the camera, as a child of the object, will rotate and translate with it

We need scientific Internet access to some websites. :rofl:

Yes, I should have used that terminology. The camera stick (CamObj) is a child of the object of interest and the Camera is a child of CamObj. To make the camera orbit the object, you change the x/y rotation of CamObj.

In the image you posted, if the person is the image of interest, you can make CamObj a child of the person and then make the camera orbit the person.

Or, if you want the camera to trail the person, you would simply rotate CamObj to a fixed location (e.g. y-rotation = 180 and x-rotation = 30).

To avoid confusion, one thing you will want to decide is whether to make the angles represent the location of the camera relative to the object or to have them represent the direction the camera is pointing. I think the latter makes more sense, but you may have to make some slight changes to the sample code above.

ADD
I believe that you merely have to flip the sign of the Y value (latitude) and add 180 degrees to the X value (longitude).

Thank you for your reply. I have made an example here, but there are still problems in some details.

Now that I see what you are doing, I wonder if it would be better to use some version of the pointerlockcontrols.js routine? That routine allows you to rotate and also to “strafe” (i.e. move forward, backwards, left and right). It is designed for first person simulations, where you are the character, but perhaps there is a way to modify it to act on a character located directly in front of your camera?

Or perhaps you can use the code as a template for creating your own version?

I used a stripped-down version in my flight simulation but all I wanted was a subroutine to capture changes in mouse position, rather than mouse screen position - which is what you normally get.

Now I use some methods in pointerlockcontrols to update the coordinates. Among them, I also add pressing and holding the middle of the mouse to rotate the camera :laughing: