OpenGL物体在移动一定距离后会震动

5

我有一个物体在地形上移动,并有一个第三人称摄像机跟随它。当我将它向不同方向移动一段距离后,即使它没有移动,摄像机围绕它旋转时也会出现抖动或震动。这是该物体的移动代码:

double& delta = engine.getDeltaTime();
GLfloat velocity = delta * movementSpeed;
glm::vec3 t(glm::vec3(0, 0, 1) * (velocity * 3.0f));
//translate the objet atri before rendering
matrix = glm::translate(matrix, t);
//get the forward vetor of the matrix
glm::vec3 f(matrix[2][0], matrix[2][1], matrix[2][2]);
f = glm::normalize(f);
f = f * (velocity * 3.0f);
f = -f;
camera.translate(f);

相机旋转是

void Camera::rotate(GLfloat xoffset, GLfloat yoffset, glm::vec3& c, double& delta, GLboolean constrainpitch) {
    xoffset *= (delta * this->rotSpeed);
    yoffset *= (delta * this->rotSpeed);
    pitch += yoffset;
    yaw += xoffset;
    if (constrainpitch) {
        if (pitch >= maxPitch) {
            pitch = maxPitch;
            yoffset = 0;
        }
        if (pitch <= minPitch) {
            pitch = minPitch;
            yoffset = 0;
        }
    }
    glm::quat Qx(glm::angleAxis(glm::radians(yoffset), glm::vec3(1.0f, 0.0f, 0.0f)));
    glm::quat Qy(glm::angleAxis(glm::radians(xoffset), glm::vec3(0.0f, 1.0f, 0.0f)));
    glm::mat4 rotX = glm::mat4_cast(Qx);
    glm::mat4 rotY = glm::mat4_cast(Qy);
    view = glm::translate(view, c);
    view = rotX * view;
    view = view * rotY;
    view = glm::translate(view, -c);
}

我添加了一些更多信息的答案。 - Spektre
2个回答

3
  1. float有时不够用。

    我在CPU端使用double精度矩阵来避免这些问题。但由于你在Android上,这可能是不可能的。对于GPU,请再次使用float,因为目前还没有64位插值器。

  2. 大数通常是问题所在

    如果你的世界很大,那么你将把大数传递到方程中,从而使任何错误乘以,并且只有在最后阶段才相对于相机位置翻译该物体,这意味着错误仍然被乘以,但数字已经被限制,因此误差/数据比例变大。

    在渲染之前将所有顶点转换为以相机为原点或附近的坐标系。你可以忽略旋转,只偏移位置。

    这样,您只会在远离相机的地方得到更高的误差,这在透视图中无法看到... 有关更多信息,请参见:

  3. 使用累积变换矩阵而不是欧拉角

    有关更多信息,请参见理解4x4同次变换矩阵和该答案底部的所有链接。


2
是的,这是一个大数问题,但使用GLSL中的高精度解决了这个问题。 - Mohamed Mousa El-Kheshen

3

这听起来像是数值效应。即使来自游戏对象的微小偏移也会对后续摄像机的旋转产生影响,导致物体/摄像机看起来像在震动。

因此,您可以:

  • 检查移动是否超过阈值值,然后再为摄像机计算新的旋转
  • 当您超过此阈值时:使用四元数Lerp算法在旧旋转和新旋转之间进行线性插值(请参见此Unity答案,以更好地了解代码: Unity lerp discussion

1
我为相机旋转制作了线性插值 xoffset = glm::mix(xoffset, nx,(GLfloat) delta);,但并没有解决问题。震动的是物体本身而不是相机,我通过添加 glm::vec3 t(glm::vec3(0, 0, 1) * (velocity * 3.0f)); 到其方向向量来移动它。那么,如果可以的话,我能为该翻译向量制作线性插值吗?用什么方法? - Mohamed Mousa El-Kheshen
1
从旧位置到新位置,我猜。 - KimKulling
1
我将代码更改为以下内容:glm :: vec3 opos = getPosition(); glm :: vec3 t(glm :: vec3(0,0,1)*(velocity * 3.0f)); glm :: mat4 nmat(matrix); nmat = glm :: translate(matrix,t); glm :: vec3 npos(nmat [3]); glm :: vec3 ipos = glm :: mix(npos,opos,(GLfloat)delta); matrix [3] = glm :: vec4(ipos,1.0f); glm :: vec3 f(matrix [2] [0],matrix [2] [1],matrix [2] [2]); f = -glm :: normalize(f)*(velocity * 3.0f); camera->translate(f); 我获取旧位置并将翻译应用于临时矩阵,然后获取位置并使用glm :: mix进行插值,但未解决。 - Mohamed Mousa El-Kheshen
1
问题出在着色器精度上,当我将其从中等设置为高时,震动就消失了。通过插值,结果变得非常好。谢谢。 - Mohamed Mousa El-Kheshen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接