3d相机有意外的滚动

时间:2017-02-16 01:40:49

标签: c++ opengl camera quaternions

我一直在使用C ++在opengl中使用3d相机。

当我用相机环顾四周时,相机中有时会出现意外晃动,尤其是当我将相机转动成圈时。

我怀疑这是一个浮点错误,但我不知道如何检测它。

这是相机类:

#ifndef CAMERA_H
#define CAMERA_H

#include <GL/glew.h>

#include <GLFW/glfw3.h>

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp>
#include <glm/gtx/rotate_vector.hpp>
#include <glm/gtx/euler_angles.hpp>
#include <glm/gtx/string_cast.hpp>

#include <iostream>

using glm::vec3;
using glm::mat4;
using glm::quat;

enum CamDirection {
    CAM_FORWARD,
    CAM_BACKWARD,
    CAM_LEFT,
    CAM_RIGHT
};


class Camera {
public:
    void cameraUpdate();

    mat4 getViewMatrix();

    Camera();

    Camera(vec3 startPosition);

    void move(CamDirection dir, GLfloat deltaTime);

    void look(double xOffset, double yOffset);

    void update();

private:
    mat4 viewMatrix;

    const GLfloat camSpeed = 5.05f;

};

mat4 Camera::getViewMatrix() {
    return viewMatrix;
}

Camera::Camera(){}


Camera::Camera(vec3 startPos):
    viewMatrix(glm::lookAt(startPos, vec3(0.0f, 0.0f, 0.0f), vec3(0.0f, 1.0f, 0.0f)))
{}

void Camera::move(CamDirection dir, GLfloat deltaTime) {
    mat4 trans;
    const vec3 camForward = vec3(viewMatrix[0][2], viewMatrix[1][2], viewMatrix[2][2]);
    const vec3 camRight   = vec3(viewMatrix[0][0], viewMatrix[1][0], viewMatrix[2][0]);

    if (dir == CAM_FORWARD)
        trans = glm::translate(trans,      (camSpeed * deltaTime) * camForward);
    else if (dir == CAM_BACKWARD)
        trans = glm::translate(trans, -1 * (camSpeed * deltaTime) * camForward);
    else if (dir == CAM_RIGHT)
        trans = glm::translate(trans, -1 * (camSpeed * deltaTime) * camRight);
    else
        trans = glm::translate(trans,      (camSpeed * deltaTime) * camRight);

    viewMatrix *= trans;
}

void Camera::look(double xOffset, double yOffset) {
    // 2 * acos(q[3])
    quat rotation = glm::angleAxis((GLfloat)xOffset, vec3( 0.0f, 1.0f, 0.0f));

    viewMatrix = glm::mat4_cast(rotation) * viewMatrix;

    rotation = glm::angleAxis((GLfloat)yOffset, vec3(-1.0f, 0.0f, 0.0f));

    mat4 rotMatrix = glm::mat4_cast(rotation);

    viewMatrix = rotMatrix * viewMatrix;
}

void Camera::update() {
}
#endif // CAMERA_H

2 个答案:

答案 0 :(得分:1)

我设法搞清楚了。虽然我不得不完全重写它来做它。

我的问题出在这些方面:

quat rotation = glm::angleAxis((GLfloat)xOffset, vec3( 0.0f, 1.0f, 0.0f));

viewMatrix = glm::mat4_cast(rotation) * viewMatrix;

rotation = glm::angleAxis((GLfloat)yOffset, vec3(-1.0f, 0.0f, 0.0f));

mat4 rotMatrix = glm::mat4_cast(rotation);

构建一个用于存储方向的中间四元数而不是工作,我可以用这个代替look方法:

quat pitch = quat(vec3(-yOffset, 0.0f, 0.0f));
quat yaw = quat(vec3(0.f, xOffset, 0.f));

orientation = pitch * orientation * yaw;

通过将方向乘以最后一行的方式,不会发生意外的滚动。

答案 1 :(得分:0)

该代码有两个问题:

首先,如果xOffsetyOffset只是屏幕像素差异(通过鼠标位置获得),则必须设置一个将其转换为角度的因子。有更好的方法,例如从窗口中心到鼠标位置(前一个和当前)形成两个向量,并通过点积计算它们之间的角度。根据glm集(默认为度,但您可以设置弧度),非因子化xOffset可能是一个巨大的角度,而不是平滑的旋转。

newViewMatrix = thisMouseRotation * oldViewMatrix的第二次累积旋转在一些运动后退化矩阵。 这是由于计算机代表数量有限:例如10/3 = 3.333但3.333 * 3 = 9.999!= 10

解决方案:

  • A)将旋转存储在四元数中。初始化四元数和 为每个轮换newQuater = thisMoveQuater * oldQuater更新它。
    不时地&#34;正常化&#34;四元数以便最小化 数字问题。
    viewMatrix由viewMatrix = Mat4x4FromQuaternion * translationMatrix计算,因此我们避免使用前一个 viewMatrix及其问题。
  • B)围绕每个 X,Y,Z轴累积旋转角度。计算 每次使用这些积累时都需要旋转矩阵 角。也许你将角度值钳制到0.2 度。这样,用户可以实现与几个相同的位置 之前的轮换。