Can't position camera behind ship && lookAt ship at the same time, using Quaternions

Hi. I been working one like a 3d portolio in three js with vanilla js. I currently cant figure out how to control the camera properly with Quaternions. Right now its working just as intended besides the fact that its in front of the ship looking backwards. So all my controls are reversed and ship is moving backwards. I have watched two long video expanations on the subject and I dont really get it yet. I tried a lot of different ways to make it work, currently Im using chatGPTs solution for the camera. But she cant seem to help me fix the reversing of the camera. If I play around with the position.set or mess around with the axises i can get the camera behind the ship but for the life of me i cant make the camera look at the ship at the same time.

Whole project is here: GitHub - RichardWallnerstrom/portfolio: 3d animated portfolio using three js and vanilla js

The methods controlling the camera are inside CameraController.js and is also posted below here.

Greatful for help on how to fix my methods.

    placeCameraBehindShip() {
        const trailingOffset = new THREE.Vector3(20, 20, 20)    
        const behindShipVector = new THREE.Vector3(0, 0, -1)    // Create a new vector (0, 0, -1) representing a direction behind the ship   
        behindShipVector.applyQuaternion(this.spaceShip.model.quaternion) // Apply the ship's quaternion to the behindShipVector
        behindShipVector.multiplyScalar(-trailingOffset.z)     // Multiply the vector by the negative of the z-component of the trailing offset
        const cameraPosition = this.spaceShip.model.position.clone().add(behindShipVector)
        this.camera.position.copy(cameraPosition)
        this.spaceShip.model.getWorldQuaternion(this.camera.quaternion) // Set camera quaternion
    }
    lookAtObject() {
        if (this.isMouseOverEarth) {
            this.camera.lookAt(this.earth.model.position);
            this.camera.updateProjectionMatrix(); 
        } else if (this.isMouseOverMars) {
            this.camera.lookAt(this.mars.model.position);
            this.camera.updateProjectionMatrix(); 
        } else {
            this.placeCameraBehindShip();
        }
    }

Most likely I misunderstand something. When I try a model with random position and orientation, setting the camera to look at the back side of the model is just this:

// set the camera 10 units behind the ship
camera.position.set( 0, 0, 10 );
model.localToWorld( camera.position );
			
// turn the camera towards the ship
camera.quaternion.copy( model.quaternion );

You can try it live here: https://codepen.io/boytchev/pen/oNmBVYJ (see lines 81-86). In my case, the back is along the model’s local positive Z axis.

2 Likes

Thanks for the reply! Been busy with other school projects. The version you showed me works fine for placing the camera behind the ship. But if i barrel roll the ship it doesnt follow it properly. Thats my fault for explaining badly.

I realize Im probably over complicating it since I dont really understand Quaternions. I been reading more about them.
I think I know the issue but not sure how to fix it.

the behindShipVector is used to decide the cameras position but also its rotation.


      const behindShipVector = new THREE.Vector3(0, 0, -1)  
      behindShipVector.applyQuaternion(this.spaceShip.model.quaternion) 
      behindShipVector.multiplyScalar(trailingOffset.z)

Here -1 means backwards. Then we apply quaternions on the behindShipVectors reference vectors. So in my head this should flip the Z axis making the camera facing the same way as the ship.

So either its the Vectors not being transformed properly, or what I believe is that something keeps telling the camera to look in the original behindShipVector direction. Im guessing its this line right here:

        const cameraPosition = this.spaceShip.model.position.clone().add(behindShipVector)

I been experimenting with different versions of that line but so far havent gotten it to work.

In this case, I’m afraid, I am not able to help you, as now I’m sure I do not understand what you want to achieve.

If you have some time, here are three short videos of a flying spaceship using rotations around all 3 axes, so it is more complex than a barrel roll:

Video 1 - static camera

The camera position is static in respect to the spaceship + the camera orientation is fixed. This video is just to have an idea about the motion of the spaceship. The same motion is used in the next two videos.

Video 2 - hard camera

The camera is fixed right behind the spaceship and is looking towards it. Camera’s position and rotation are set the same way as in my previous reply (the one that you labeled as “doesn’t follow properly”).

Video 3 - soft camera

Just for fun I made a soft camera that follows the spaceship with some smoothness. The code is almost the same, but instead of setting camera’s position and quaternion, they are lerp-ed and slerp-ed.

In any case, good luck with your school project. I hope that you will eventually manage to position the camera as you want.

2 Likes

You may want to try setting the up vector before you do the lookAt of the camera…

At init time:
camera.up = camera.up.clone()

Before you do your camera.lookAt( ship )


camera.up.set(0,1,0).applyQuaternion(ship);
camera.lookAt(ship)
1 Like

Sorry for not getting back here been really busy with school and getting married :D. I really appreciate all the feedback now I finally have 2 weeks to work on this again.