OpenGL浮点精度会产生意外的差异

时间:2017-07-04 11:18:49

标签: c++ opengl precision glm-math

我有一个功能可以通过偏航和俯仰角度围绕玩家旋转相机。

void Camera::updateVectors() {
    GLfloat radius = glm::length(center - position);
    position.x = cos(glm::radians(this->yaw)) * cos(glm::radians(this->pitch));
    position.y = sin(glm::radians(this->pitch));
    position.z = sin(glm::radians(this->yaw)) * cos(glm::radians(this->pitch));
    position *= radius;
    this->front = glm::normalize(center - position);
    this->right = glm::normalize(glm::cross(this->front, this->worldUp));
    this->up = glm::normalize(glm::cross(this->right, this->front));
    lookAt = glm::lookAt(this->position, this->position + this->front, this->up);
}

当我移动播放器时,相机应随之移动,方法是在相机的中心和位置添加平移矢量:

void Camera::Transform(glm::vec3& t) {
    this->position += t;
    this->center += t;
}

在移动播放器之前,相机旋转工作正常并且播放器移动也能正常工作但是一旦我尝试在播放器移动后旋转相机,它就会开始意外地改变位置。

enter image description here

在进行一些调试后,我注意到在第一行计算的半径,即相机的中心和位置之间的距离,如49.888889或50.000079,并且由于初始化值应为50.0,这个非常小的差异使得结果出人意料。 那么我怎么能处理这个浮点精度,或者我的代码或计算中是否存在错误。

编辑:  球员的位置取决于其偏航和俯仰并更新相机的中心

GLfloat velocity = this->movementSpeed * deltaTime;
if (direction == FORWARD) {
    glm::vec3 t = glm::vec3(sin(glm::radians(yaw)), sin(glm::radians(pitch)), cos(glm::radians(yaw))) * velocity;
    matrix = glm::translate(matrix, t);
    for (GLuint i = 0; i < this->m_Entries.size(); i++) {
        this->m_Entries[i].setModelMatrix(matrix);
    }
    glm::vec3 f(matrix[2][0], matrix[2][1], matrix[2][2]);
    f *= velocity;
    scene->getDefCamera()->Transform(f);
}
if (direction == BACKWARD) {
    glm::vec3 t = glm::vec3(sin(glm::radians(yaw)), 0.0, cos(glm::radians(yaw))) * velocity;
    matrix = glm::translate(matrix, -t);
    for (GLuint i = 0; i < this->m_Entries.size(); i++) {
        this->m_Entries[i].setModelMatrix(matrix);
    }
    glm::vec3 f(matrix[2][0], matrix[2][1], matrix[2][2]);
    f *= velocity;
    f = -f;
    scene->getDefCamera()->Transform(f);
}

2 个答案:

答案 0 :(得分:3)

这里的主要问题是你是根据正在移动的位置进行旋转。但是旋转是基于坐标系的原点。因此,当您移动位置时,相对于原点仍在进行旋转。

而不是Transform偏移position,它应该只偏移center。实际上,存储position毫无意义;根据当前的中心点,半径和旋转角度,计算摄像机的位置。半径是应该存储的属性,而不是计算的。

答案 1 :(得分:0)

解决方案只是在相机视图矩阵上进行转换,而不是通过lookAt函数进行转换  首先初始化相机

void Camera::initCamera(glm::vec3& pos, glm::vec3& center, GLfloat yaw, GLfloat pitch) {
    view = glm::translate(view, center-pos);
    view = glm::rotate(view, glm::radians(yaw), glm::vec3(0.0, 1.0, 0.0));
    view = glm::rotate(view, glm::radians(pitch), glm::vec3(1.0, 0.0, 0.0));
    view = glm::translate(view, pos-center);
}

然后旋转功能:

void Camera::Rotate(GLfloat xoffset, GLfloat yoffset, glm::vec3& c) {
    xoffset *= this->mouseSensitivity;
    yoffset *= this->mouseSensitivity;
    view = glm::translate(view, c );//c is the player position
    view = glm::rotate(view, glm::radians(xoffset), glm::vec3(0.0, 1.0, 0.0));
    view = glm::rotate(view, glm::radians(yoffset), glm::vec3(1.0, 0.0, 0.0));
    view = glm::translate(view,  - c);
}

和相机移动功能:

void Camera::Translate(glm::vec3& t) {
    view = glm::translate(view, -t);
}

并且在玩家类中,当玩家移动时,推动相机通过此代码向其方向移动

void Mesh::Move(Move_Directions direction, GLfloat deltaTime) {
GLfloat velocity = 50.0f * this->movementSpeed * deltaTime;
if (direction == FORWARD) {
    glm::vec3 t = glm::vec3(sin(glm::radians(yaw)), sin(glm::radians(pitch)), cos(glm::radians(yaw))) * velocity;
    matrix = glm::translate(matrix, t);
    for (GLuint i = 0; i < this->m_Entries.size(); i++) {
        this->m_Entries[i].setModelMatrix(matrix);
    }
    glm::vec3 f(matrix[2][0], matrix[2][1], matrix[2][2]);
    f *= velocity;
    scene->getDefCamera()->Translate(f);
}
if (direction == BACKWARD) {
    glm::vec3 t = glm::vec3(sin(glm::radians(yaw)), 0.0, cos(glm::radians(yaw))) * velocity;
    matrix = glm::translate(matrix, -t);
    for (GLuint i = 0; i < this->m_Entries.size(); i++) {
        this->m_Entries[i].setModelMatrix(matrix);
    }
    glm::vec3 f(matrix[2][0], matrix[2][1], matrix[2][2]);
    f *= velocity;
    f = -f;
    scene->getDefCamera()->Translate(f);
}
if (direction == RIGHT) {
    matrix = glm::rotate(matrix, (GLfloat) -M_PI * deltaTime, glm::vec3(0.0, 1.0, 0.0));
    for (GLuint i = 0; i < this->m_Entries.size(); i++) {
        this->m_Entries[i].setModelMatrix(matrix);
    }
}
if (direction == LEFT) {
    matrix = glm::rotate(matrix, (GLfloat) M_PI * deltaTime, glm::vec3(0.0, 1.0, 0.0));
    for (GLuint i = 0; i < this->m_Entries.size(); i++) {
        this->m_Entries[i].setModelMatrix(matrix);
    }
}
}

感谢每个人的帮助