Making a fixed camera system and having trouble with gimbal lock
I'm trying to make a fixed camera system reminiscent to MGS2's. So far I've got panning on induvidual axises working fine, but I'm struggling with rotation. I've managed to get induvidual axises of the camera to rotate relative to the player, but they'll only do this whithin certain intervals, so once the player moves a certain distance (or reaches a certain coordinate) the rotation will jerk or reverse suddenly.
I know this is likely due to gimbal lock, but I don't know what quaternion functions to use in order to acheive an effect like this with full 360 degree rotation.
Also, as I'm new to coding, there's probably a way better more efficient way to do this (likely with far less Vector3s and if statements). I'm very aware that I may be doing this completely wrong so any criticism or general advice is appreciated.
{
public float smoothSpeed;
//is the camera translating towards player
public bool pan;
public bool pitch;
public bool roll;
public bool yaw;
public bool followX;
public bool followY;
public bool followZ;
public bool lookX;
public bool lookY;
public bool lookZ;
public bool justRotate;
public Transform player;
//defines camera translation
Vector3 desiredPos;
Vector3 panSmoothResult;
private Vector3 panPosX;
private Vector3 panPosY;
private Vector3 panPosZ;
private Vector3 panPosXY;
private Vector3 panPosYZ;
private Vector3 panPosXZ;
private Vector3 panPosXYZ;
public Vector3 defaultRotation;
private Quaternion _defaultRotation;
public Vector3 panOffset;
public Vector3 lookOffset;
public Vector3 wallHugOffset;
public Vector3 firstPersonPosOffset;
//the vars I'd like to use to control rotation
[SerializeField]
Vector3 desiredRot;
Quaternion _desiredRot;
[SerializeField]
Quaternion lookSmoothResult;
Vector3 lookAxis;
[SerializeField]
Vector3 lookPosition;
public float lookSpeed;
//first person and wallhug vars
public bool wallHug;
Vector3 firstPersonPos;
Vector3 firstPersonTransition;
public bool firstPerson;
public Transform playerHead;
Vector3 wallHugPos;
Vector3 wallHugRot;
Vector3 wallHugTransition;
void FixedUpdate () {
//set vectors
_defaultRotation.eulerAngles = defaultRotation;
panPosX.Set(player.position.x, 0f, 0f);
panPosY.Set(0f, player.position.y, 0f);
panPosZ.Set(0f,0f, player.position.z);
panPosXY = panPosX + panPosY;
panPosXZ = panPosX + panPosZ;
panPosYZ = panPosY + panPosZ;
panPosXYZ = player.position;
firstPersonPos = playerHead.position + firstPersonPosOffset;
wallHugPos = player.position + wallHugOffset;
lookPosition= player.position * lookSpeed;
if(firstPerson){
pan = false;
pitch = false;
roll = false;
yaw = false;
wallHug = false;
FirstPersonPosition();
}
if(!firstPerson && !wallHug){
pan = true;
transform.rotation = _defaultRotation;
}
if(wallHug){
pan = false;
firstPerson = false;
WallHugPosition();
}
if(!firstPerson && !wallHug && justRotate){
pan = false;
}
if (pan) {
if(followX && followY && followZ && pan){
PanCamera (panPosXYZ);
}
else if(followX && followY && pan){
PanCamera (panPosXY);
}
else if(followX && followZ && pan){
PanCamera (panPosXZ);
}
else if(followY && followZ && pan){
PanCamera (panPosYZ);
}
else if(followX && pan){
PanCamera (panPosX);
}
else if(followY && pan){
PanCamera (panPosY);
}
else if (followZ && pan){
PanCamera (panPosZ);
}
}
**if(pitch || roll || yaw){
if(lookX && pitch){
lookAxis.Set (lookPosition.x, 0f, 0f);
LookCamera (lookAxis);
}
else if(lookY && pitch){
lookAxis.Set (lookPosition.y, 0f, 0f);
LookCamera (lookAxis);
}
else if(lookZ && pitch){
lookAxis.Set (lookPosition.z, 0f, 0f);
LookCamera (lookAxis);
}
else if(lookX && roll){
lookAxis.Set (0f, lookPosition.x, 0f);
LookCamera (lookAxis);
}
else if(lookY && roll){
lookAxis.Set (0f, lookPosition.y, 0f);
LookCamera (lookAxis);
}
else if(lookZ && roll){
lookAxis.Set (0f, lookPosition.z, 0f);
LookCamera (lookAxis);
}
else if(lookX && yaw){
lookAxis.Set (0f, 0f, lookPosition.x);
LookCamera (lookAxis);
}
else if(lookY && yaw){
lookAxis.Set (0f, 0f, lookPosition.y);
LookCamera (lookAxis);
}
else if(lookZ && yaw){
lookAxis.Set (0f, 0f, lookPosition.z);
LookCamera (lookAxis);
}
else if(lookX && pitch && roll){
lookAxis.Set (lookPosition.x,lookPosition.x,0f);
LookCamera (lookAxis);
}
else if(lookY && pitch && roll){
lookAxis.Set (lookPosition.y,lookPosition.y,0f);
LookCamera (lookAxis);
}
else if(lookZ && pitch && roll){
lookAxis.Set (lookPosition.z,lookPosition.z,0f);
LookCamera (lookAxis);
}
else if(lookZ && pitch && roll){
lookAxis.Set (lookPosition.z,lookPosition.z,0f);
LookCamera (lookAxis);
}
else if(lookX && pitch && yaw){
lookAxis.Set (lookPosition.x,0f, lookPosition.x);
LookCamera (lookAxis);
}
else if(lookY && pitch && yaw){
lookAxis.Set (lookPosition.y,0f, lookPosition.y);
LookCamera (lookAxis);
}
else if(lookX && roll && yaw){
lookAxis.Set (0f, lookPosition.x, lookPosition.x);
LookCamera (lookAxis);
}
else if(lookY && roll && yaw){
lookAxis.Set (0f, lookPosition.y, lookPosition.y);
LookCamera (lookAxis);
}
else if(lookZ && roll && yaw){
lookAxis.Set (0f, lookPosition.z, lookPosition.z);
LookCamera (lookAxis);
}**
}
}
/// generic functions for panning
public Vector3 PanOffset(Vector3 panPos)
{
desiredPos = panPos + panOffset;
return desiredPos;
}
**public Quaternion LookOffset(Vector3 lookAxis){
desiredRot = lookAxis + lookOffset;
_desiredRot.eulerAngles = desiredRot;
return _desiredRot;
}**
public Vector3 PanSmooth (Vector3 desiredPosition)
{
panSmoothResult = Vector3.Lerp (transform.position, desiredPos, smoothSpeed);
return panSmoothResult;
}
**public Quaternion LookSmooth (Quaternion _desiredRot){
lookSmoothResult = Quaternion.Lerp(transform.rotation, _desiredRot, smoothSpeed);
return lookSmoothResult;
}**
void PanCamera(Vector3 panAxis)
{
PanOffset (panAxis);
PanSmooth (desiredPos);
transform.position = panSmoothResult;
}
**void LookCamera(Vector3 lookAxis){
LookOffset (lookAxis);
LookSmooth (_desiredRot);
transform.rotation = lookSmoothResult;
}**
void FirstPersonPosition()
{
//would be nice to have this run once before
firstPersonTransition = Vector3.Lerp (transform.position, firstPersonPos, smoothSpeed);
transform.position = firstPersonPos;
transform.rotation = playerHead.rotation;
transform.Rotate(0f, 0f, 90f);
}
void WallHugPosition(){
wallHugTransition = Vector3.Lerp (transform.position, wallHugPos, smoothSpeed);
transform.position = wallHugTransition;
transform.LookAt (playerHead.position);
}
}