Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/opengl/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 旋转精度误差积累得太快?_C++_Opengl_Glm Math - Fatal编程技术网

C++ 旋转精度误差积累得太快?

C++ 旋转精度误差积累得太快?,c++,opengl,glm-math,C++,Opengl,Glm Math,当一个接一个地应用旋转时,精度误差会累积 但我很惊讶错误累积得如此之快 在这个例子中,我比较了两个理论上等价的变换 在实践中,我只做了两次旋转而不是一次旋转,就得到了0.02度的误差 我原以为误差会小一些 有没有办法使这两种转换的结果更接近?而不是使用双精度变量 #include <glm/gtx/rotate_vector.hpp> double RadToDeg(double rad) { return rad * 180.0 / M_PI; } const glm

当一个接一个地应用旋转时,精度误差会累积

但我很惊讶错误累积得如此之快

在这个例子中,我比较了两个理论上等价的变换

在实践中,我只做了两次旋转而不是一次旋转,就得到了0.02度的误差

我原以为误差会小一些

有没有办法使这两种转换的结果更接近?而不是使用双精度变量

#include <glm/gtx/rotate_vector.hpp>

double RadToDeg(double rad) 
{
    return rad * 180.0 / M_PI;
}

const glm::vec3 UP(0, 0, 1);

void CompareRotations()
{
    glm::vec3 v0 = UP;
    glm::vec3 v1 = glm::normalize((glm::vec3(0.0491, 0.0057, 0.9987)));
    glm::vec3 v2 = glm::normalize((glm::vec3(0.0493, 0.0057, 0.9987)));

    glm::vec3 axis_0_to_1 = glm::cross(v0, v1);
    glm::vec3 axis_1_to_2 = glm::cross(v1, v2);
    glm::vec3 axis_global = glm::cross(v0, v2);

    float angle_0_to_1 = RadToDeg(acos(glm::dot(v0, v1)));
    float angle_1_to_2 = RadToDeg(acos(glm::dot(v1, v2)));
    float angle_global = RadToDeg(acos(glm::dot(v0, v2)));

    glm::vec3 v_step = UP;
    v_step = glm::rotate(v_step, angle_0_to_1, axis_0_to_1);
    v_step = glm::rotate(v_step, angle_1_to_2, axis_1_to_2);

    glm::vec3 v_glob = UP;
    v_glob = glm::rotate(v_glob, angle_global, axis_global);

    float angle = RadToDeg(acos(glm::dot(v_step, v_glob)));
    if (angle > 0.01)
    {
       printf("error");
    }
}
#包括
双RadToDeg(双rad)
{
返回rad*180.0/M_PI;
}
常量glm::vec3 UP(0,0,1);
void CompareRotations()
{
glm::vec3 v0=上升;
glm::vec3 v1=glm::normalize((glm::vec3(0.0491,0.0057,0.9987));
glm::vec3 v2=glm::normalize((glm::vec3(0.0493,0.0057,0.9987));
glm::vec3轴0到1=glm::交叉(v0,v1);
glm::vec3轴1到2=glm::交叉(v1,v2);
glm::vec3轴\u全局=glm::交叉(v0,v2);
浮球角度_0_至_1=RadToDeg(acos(glm::dot(v0,v1));
浮动角度_1_至_2=RadToDeg(acos(glm::dot(v1,v2));
浮球角度=RadToDeg(acos(glm::dot(v0,v2));
glm::vec3 v_阶跃=上升;
v_步距=glm::旋转(v_步距,角度0_至1,轴0_至1);
v_步距=glm::旋转(v_步距、角度_1_至_2、轴_1_至_2);
glm::vec3 v_glob=向上;
v_glob=glm::旋转(v_glob、角度_global、轴_global);
浮动角度=RadToDeg(acos(glm::dot(v_阶跃,v_glob));
如果(角度>0.01)
{
printf(“错误”);
}
}

如果您只想继续沿同一轴旋转,那么最好只是围绕该轴增加旋转角度,并每次从该角度重新计算一个新矩阵。请注意,您可以直接。例如,从欧拉角度构建旋转通常既不是必要的,也不是很好的解决方案(奇点、数值上不理想、行为不太直观)。有一个重载
glm::rotate()


如果必须围绕任意轴连接许多任意旋转,那么使用四元数表示旋转可能在数值上更稳定。既然您已经在使用GLM,那么您可以使用其中的。您可能会发现这很有用。

如果您只想继续沿同一轴旋转,那么最好只是围绕该轴增加旋转角度,然后每次都从该角度重新计算一个新矩阵。请注意,您可以直接。例如,从欧拉角度构建旋转通常既不是必要的,也不是很好的解决方案(奇点、数值上不理想、行为不太直观)。有一个重载
glm::rotate()


如果必须围绕任意轴连接许多任意旋转,那么使用四元数表示旋转可能在数值上更稳定。既然您已经在使用GLM,那么您可以使用其中的。您可能会发现它很有用。

浮点乘法并不像您想象的那样精确,而且每次将两个浮点数相乘时,您都会丢失精度——正如您所发现的那样,很快就会丢失精度

通常,您不希望将变换存储为结果矩阵,而是存储为获取该矩阵所需的步骤;例如,如果仅执行单轴变换,则将变换存储为角度,并每次重新计算矩阵。但是,如果涉及多个轴,这会很快变得非常复杂

另一种方法是使用转换的底层表示,该表示本身可以精确地进行转换。对于这一点非常流行(per),但另一种更容易可视化的方法是使用一对向量,以一种可以重建规范化矩阵的方式表示变换。例如,您可以将旋转视为一对向量,
向前
向上
。由此,您可以计算变换矩阵,例如:

z_axis = normalize(forward);
x_axis = normalize(cross(up, forward));
y_axis = normalize(cross(forward, x_axis));
然后用这些向量建立变换矩阵;给定这些轴和位置的
pos
(主列)OpenGL矩阵将为:

{ x_axis.x, x_axis.y, x_axis.z, 0,
  y_axis.x, y_axis.y, y_axis.z, 0,
  z_axis.x, z_axis.y, z_axis.z, 0,
  pos.x,    pos.y,    pos.z,    1 }
类似地,您可以通过从矩阵中分别提取Z和Y向量作为
方向
向上
,并从中重建新矩阵,来重新规范化变换矩阵


这确实比使用四元数需要更多的计算复杂度,但我发现这更容易理解。

浮点乘法并不像你想象的那样精确,而且每次你将两个浮点数相乘,你都会失去精度——正如你所发现的那样,相当快

通常,您不希望将变换存储为结果矩阵,而是存储为获取该矩阵所需的步骤;例如,如果仅执行单轴变换,则将变换存储为角度,并每次重新计算矩阵。但是,如果涉及多个轴,这会很快变得非常复杂

另一种方法是使用转换的底层表示,该表示本身可以精确地进行转换。对于这一点非常流行(per),但另一种更容易可视化的方法是使用一对向量,以一种可以重建规范化矩阵的方式表示变换。例如,您可以将旋转视为一对向量,
向前
向上
。由此,您可以计算变换矩阵,例如:

z_axis = normalize(forward);
x_axis = normalize(cross(up, forward));
y_axis = normalize(cross(forward, x_axis));
然后用这些向量建立变换矩阵;给定这些轴和位置的
pos
(主列)OpenGL矩阵将为:

{ x_axis.x, x_axis.y, x_axis.z, 0,
  y_axis.x, y_axis.y, y_axis.z, 0,
  z_axis.x, z_axis.y, z_axis.z, 0,
  pos.x,    pos.y,    pos.z,    1 }
类似地,您可以通过从矩阵中提取Z和Y向量,分别作为
方向
向上
,并重建新的变换矩阵来重新规范化变换矩阵