基于四元数的相机不需要的滚动

Quaternion-based camera unwanted roll

我基于四元数创建了一个相机,但是当我转动相机时,出现了不需要的滚动。我不想失去使用例如欧拉角的运动自由度,因为有时需要添加滚动。如果我使用欧拉角,那么据我所知,我可以获得一个万向节锁。

代码:

struct FreeCamera : public BaseCamera {
    float pitch = 0, yaw = 0, roll = 0;

    void updateView();

private:
    glm::quat qCamera;
};

struct FreeCameraController: public BaseCameraController {
    float sensitivityPitch = 0.0025f, sensitivityYaw = 0.0025f, sensitivityRoll = 0.0025f;

    void mouseMove(const float x, const float y, const float z = 0);

    inline void setMousePos(const float x, const float y, const float z = 0) {
        lastMousePos = glm::vec3(x, y, z);
    }

private:
    glm::vec3 lastMousePos = glm::vec3(0.0f);
};

void FreeCamera::updateView() {
    // temporary frame quaternion from pitch, yaw, roll
    glm::quat qPYR = glm::quat(glm::vec3(pitch, yaw, roll));
    // reset values
    pitch = yaw = roll = 0;

    // update qCamera
    qCamera = qPYR * qCamera;
    qCamera = glm::normalize(qCamera);
    glm::mat4 rotate = glm::mat4_cast(qCamera);

    glm::mat4 translate = glm::mat4(1.0f);
    translate = glm::translate(translate, -pos);

    view = rotate * translate;
}

void FreeCameraController::mouseMove(const float x, const float y, const float z) {
    glm::vec3 dCoord = glm::vec3(x, y, z) - lastMousePos;

    ((FreeCamera*)camera)->yaw = dCoord.x * sensitivityYaw;
    ((FreeCamera*)camera)->pitch = dCoord.y * sensitivityPitch;
    ((FreeCamera*)camera)->roll = dCoord.z * sensitivityRoll;

    lastMousePos = glm::vec3(x, y, z);
}

是否可以重置不需要的滚动,"stabilize" 相机?

因为你想阻止滚动(如果是汽车,也可能偏航,因为你会让汽车飞起来),你必须通过连接旋转来阻止其中一个轴。您想要实现的是实际的万向节锁定(您在飞行时使用包含所有旋转的单个四元数来专门摆脱它)。因此,假设您可以检测到车辆是否在地面上:

glm::mat4 rotationMatrix;
// When you want to get rid of any axis rotation, you must lock it
if(onGround)
{
    glm::quat yawQ = glm::quat(glm::vec3(0.0f, yaw, 0.0f));
    yawQ = glm::normalize(yawQ);
    glm::mat4 yawMat = glm::mat4_cast(yawQ);

    glm::quat pitch = glm::quat(glm::vec3(pitch, 0.0f, 0.0f));
    pitch = glm::normalize(pitch);
    glm::mat4 pitchMat = glm::mat4_cast(pitch);

    rotationMatrix = pitchMat * yawMat;
}
else
{
  //Your computation
  rotationMatrix = glm::mat4_cast(yourQuaternion);
}

viewMatrix = rotationMatrix * translationMatrix;

注意不是一定要用四元数来达到gound控制的效果