0
\$\begingroup\$

https://youtu.be/13HgaeZWlIA

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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.