I am making a 3D space shooter game using OpenGL and Bullet Physics. I am having a hard time with the 3rd person Camera though. If you take a look at the video above you can see that the camera follows the spaceship rotating on the X axis without a problem and rotating on Z axis also without a problem when the spaceship is is oriented towards the horizon and parallel to the ground. When I roll to the right and move the spaceship up I am totally losing it from the camera. The code for my camera is as follows :
float CalculateHorizontalDistance() {
if (!mpPlayer) return 0.f;
return distanceFromPlayer * glm::cos(glm::radians(-UpAngle));
}
float CalculateVerticalDistance() {
if (!mpPlayer) return 0.f;
return distanceFromPlayer * glm::sin(glm::radians(-UpAngle));
}
void calculateCameraPosition(float horizDistance, float verticDistance)
{
if (!mpPlayer) return;
glm::vec3 playerFront = mpPlayer->GetFront();
glm::vec3 playerPos = mpPlayer->GetPosition();
Position = playerPos + ((-playerFront) * distanceFromPlayer);
UpAngle = 180.f - mpPlayer->GetRoll();
//RightAngle = -mpPlayer->GetPitch();
RollAngle = mpPlayer->GetYaw() - 180.f;
//float theta = mpPlayer->GetRotationY() + angleAroundPlayer;
//float offsetX = horizDistance * glm::sin(glm::radians(theta));
//float offsetZ = horizDistance * glm::cos(glm::radians(theta));
//Position.x = mpPlayer->GetPosition().x - offsetX;
//Position.y = mpPlayer->GetPosition().y + verticDistance;
//Position.z = mpPlayer->GetPosition().z - offsetZ;
}
The above code is used to calculate the position and rotation of the camera. The commented out code was used to calculate the position based on trigonometrical calculations for the x and z sides of the triangle created from the camera position to the player position. This didn't work right because I could never set the camera behind the spaceship, only the position worked well.
On the non-commented out code I use as a camera position the player position - back vector * offset. This works fine for the simple purpose that the camera is always on the back side of the spaceship. I also update pitch and roll which works almost fine and here is where I need help mostly to get this right. I also never update the yaw of the camera.
This is how I get yaw, pitch and roll from Bullet Physics rigid body of the player (spaceship):
btScalar yaw;
btScalar pitch;
btScalar roll;
body->getCenterOfMassTransform().getBasis().getEulerZYX(yaw, pitch, roll, 1);
The following code is how the orientation of the camera is calculated :
void updateCameraVectors()
{
// Yaw
glm::quat aroundY = glm::angleAxis(glm::radians(-RightAngle), glm::vec3(0, 1, 0));
// Pitch
glm::quat aroundX = glm::angleAxis(glm::radians(UpAngle), glm::vec3(1, 0, 0));
// Roll
glm::quat aroundZ = glm::angleAxis(glm::radians(RollAngle), glm::vec3(0, 0, 1));
Orientation = aroundY * aroundX * aroundZ;
glm::quat qF = Orientation * glm::quat(0, 0, 0, -1) * glm::conjugate(Orientation);
Front = { qF.x, qF.y, qF.z };
Right = glm::normalize(glm::cross(Front, WorldUp));
Up = glm::normalize(glm::cross(Right, Front));
}
and lastly how the view matrix of the camera is calculated:
glm::mat4 GetViewMatrix()
{
// You should know the camera move reversely relative to the user input.
// That's the point of Graphics Camera
glm::quat reverseOrient = glm::conjugate(Orientation);
glm::mat4 rot = glm::mat4_cast(reverseOrient);
glm::mat4 translation = glm::translate(glm::mat4(1.0), -Position);
return rot * translation;
}
Can someone help me fix the rotational problems that I am facing. I am open to modify also the Camera Class to make it work better with Bullet's quaternions instead of the Euler's angles that I am trying to use. Any code or ideas are very welcomed. Thank you for reading through.