Orbit cam without gimbal lock

Hey guys,

I need an orbit cam that can rotate around an object, and go past gimbal lock point (in other words, go all the way around an object, past the 360 degree point and keep going)

I managed to do the basics of an orbit cam with taking the vector from the camera to the target and then rotating it by multiplying it with a Quaternion.AngleAxis in the following format

Vector3 vector = transform.position-target.transform.position;
vector=Quaternion.AngleAxis(Input.GetAxisRaw("Mouse X"),transform.up)*vector;
vector=Quaternion.AngleAxis(Input.GetAxisRaw("Mouse Y"),transform.right)*vector;
    
transform.position=vector+target.transform.position;

But the only way I can figure out the rotation is via a LookAt method, and it keeps locking me at the top and bottom of the rotation.

Can you guys help?

Generally there are two orbit / FPS cam modes:

1 world space + 1 local space axis (2 axis cam)

3 local space axis (3 axis cam)

Those two approaches have some advantates and some disadvantages. When you use 1 world space axis (usually y) and one local axis (usually x) you get the usual FPS / TPS cam. You just use two float variables to hold the current angle for each axis. There’s no gimbal lock for the two axis.It’s possible to let the user rotate past ±90° up and down. However the y rotation may feel wrong when you rotate your cam upside down as it would be inverted

The other solution is to rotate around local axes only. However this approach makes it impossible to only have 2 axis because relative rotations around local axes will always allow an indirect roation around the third axis. Such a cam is used in most space games which do not have a well defined up / down (like Space Engineers). So rotating the two main axes will always be relative to the current view. In addition you need controls for the third axis (local z) which is commonly controlled with “q” and “e”. You could leave out the thrid axis but it makes navigating more difficult for the user. An example of this is the rotation of objects in Garry’s mod using the physics gun. When you hold an object and press e your two mouse axis control the rotation around your current view axis (so left/right rotates around the up axis and up/down rotates around the right axis). You can indirectly rotate around the forward axis by doing 90° around the up axis, followed by 90° around the right axis and another -90° around the up axis.

To implement the first / common controls you just combine the absolute rotations the way you like

float xRot = 0;
float yRot = 0;

void Update()
{
    xRot += Input.GetAxis("Mouse Y") * ySensitivity;
    yRot += Input.GetAxis("Mouse X") * xSensitivity;
    transform.rotation = Quaternion.Euler(0,yRot,0) * Quaternion.Euler(xRot,0,0);
}

For the second solution you would do something like:

void Update()
{
    transform.Rotate(Input.GetAxis("Mouse Y") * ySensitivity, 0, 0);
    transform.Rotate(0, Input.GetAxis("Mouse X") * xSensitivity, 0);
    transform.Rotate(0, 0, Input.GetAxis("Rotate Z") * zSensitivity * Time.deltaTime);
}

For this you have to create a new axis in the input manager called “Rotate Z”. Assign “q” and “e” as the positive and negative buttons. Of course if you don’t want to provide direct z rotation just remove the third line.

Independent from the way how to rotate the camera, you just want to place it at the set orbit distance relative to the target by using this line:

transform.position = target.position - transform.forward * orbitDistance;

Here “target” is the Transform reference of your target object that you want to orbit. If you don’t want to orbit a certain object but just a position, just replace target.position with your desired center. Of course if you want to orbit around the world origin (0,0,0) you would just do

transform.position = -transform.forward * orbitDistance;