Search code examples
c++visual-studio-2017quaternionsglm-math

Unwanted Roll on FPS Camera


So just recently I've been learning to use quaternions, I got an fps camera going but I get some "unwanted" roll when rotating from the local up and right vectors, however I'm pretty sure this is normal, but how do I prevent it from doing that? I tried a few methods from here and here, both did not work and gave weird results when rotating the camera. Any help would be appreciated!

Download Executable

void Transform::Update()
{
    transform = position * glm::toMat4(quatRot) * scale;
}

void Transform::ApplyRotation(glm::vec3 rot, bool isDegr = true)
{
    if (isDegr)
        quatRot = glm::quat(GetRads(rot)) * quatRot;
    else
        quatRot = glm::quat(rot) * quatRot;
}

glm::vec3 Transform::Forward() const
{
    return glm::normalize(glm::vec3(transform[2][0], transform[2][1], transform[2][2]));
}

glm::vec3 Transform::Right() const
{
    return glm::normalize(glm::vec3(transform[0][0], transform[0][1], transform[0][2]));
}

glm::vec3 Transform::Up() const
{
    return glm::normalize(glm::vec3(transform[1][0], transform[1][1], transform[1][2]));
}

void FPCamera::Update()
{
    Transform *trans = GetOwner()->GetTransform();

    Vec2_i difference = GetWindow()->GetDifference();

    glm::vec3 tmpDiff(-(static_cast<float>(difference[1]) * 0.5f), -(static_cast<float>(difference[0]) * 0.5f), 0.0f);

    trans->ApplyRotation(trans->Right() * tmpDiff[0]);
    trans->ApplyRotation(trans->Up() * tmpDiff[1]);

    view = glm::inverse(trans->GetMatrix());
}

Solution

  • I found the answer, when I used this solution, I didn't know I needed to use world vectors instead of local vectors for the axis angles as I found from this solution.

    void Transform::ApplyRotation(glm::quat yaw, glm::quat pitch)
    {
        quatRot = pitch * quatRot * yaw;
    }
    
    void FPCamera::Update()
    {
        Transform *trans = GetOwner()->GetTransform();
    
        Vec2_i difference = GetWindow()->GetDifference();
    
        glm::vec3 tmpDiff(-(static_cast<float>(difference[1]) * 0.5f), -(static_cast<float>(difference[0]) * 0.5f), 0.0f);
    
        trans->ApplyRotation(glm::quat(GetRads(glm::vec3(tmpDiff[0], 0.0f, 0.0f))), glm::quat(GetRads(glm::vec3(0.0f, tmpDiff[1], 0.0f))));
    
        view = glm::inverse(trans->GetMatrix());
    }