3d - 四元数旋转导致场景拉伸(stretch)

标签 3d rust linear-algebra quaternions

我改编了一个Vulkano , GLTF viewer example , 允许键盘和鼠标输入,对场景应用平移和旋转。平移工作正常,但旋转会导致场景中的对象向右移动到相机并拉伸(stretch)直到它们看起来像垃圾,因为旋转接近 90 - 180 度。

这是旋转前的场景:

This is what the scene looks like before rotation .

这是旋转大约 90 度时的情况:

And this is when rotation is at approx 90 degrees .

我正在使用 cgmath Quaternions为旋转。我以前没有使用过四元数,所以我想知道是否有人可以告诉我我是否正确使用它们,我怀疑这就是问题所在。

这就是我创建初始四元数的方式,使用我找到的方程 here :

let rotation_speed_deg = 0.01;
let rotation_speed = rotation_speed_deg * f32::consts::PI / 180.0;
let rotation_angle_deg = 0.0;
let rotation_angle = rotation_angle_deg * f32::consts::PI / 180.0;
let rotation_axis = Vector3::new(0.0, 1.0, 0.0);
let rotation_scalar = (rotation_angle / 2.0 as f32).cos();
let rotation_vec = Vector3::new(
    rotation_axis.x * (rotation_angle / 2.0 as f32).sin(),
    rotation_axis.y * (rotation_angle / 2.0 as f32).sin(),
    rotation_axis.z * (rotation_angle / 2.0 as f32).sin());
let mut rotation_quat = Quaternion::from_sv(rotation_scalar, rotation_vec);

然后我修改四元数以在鼠标输入上应用旋转,如下所示:

let diff_x = position.0 - last_x;
if diff_x > 0.0 {
    // println!("turn right");
    rotation_quat.v.x += rotation_axis.x * ((rotation_angle + rotation_speed) / 2.0 as f32).sin();
    rotation_quat.v.y += rotation_axis.y * ((rotation_angle + rotation_speed) / 2.0 as f32).sin();
    rotation_quat.v.z += rotation_axis.z * ((rotation_angle + rotation_speed) / 2.0 as f32).sin();
    rotation_quat.s += ((rotation_angle + rotation_speed) / 2.0 as f32).cos();
} else if diff_x < 0.0 {
    // println!("turn left");
    rotation_quat.v.x += rotation_axis.x * ((rotation_angle - rotation_speed) / 2.0 as f32).sin();
    rotation_quat.v.y += rotation_axis.y * ((rotation_angle - rotation_speed) / 2.0 as f32).sin();
    rotation_quat.v.z += rotation_axis.z * ((rotation_angle - rotation_speed) / 2.0 as f32).sin();
    rotation_quat.s += ((rotation_angle - rotation_speed) / 2.0 as f32).cos();
}

last_x = position.0;

为了应用平移和旋转,我像这样乘以我的矩阵:

let fovy = Rad(60.0 * f32::consts::PI / 180.0);
let mut aspect = viewport_dimensions[0] as f32 / viewport_dimensions[1] as f32;
let near = 0.1;
let far = 100.0;
let mut proj = perspective(fovy, aspect, near, far);
let view = Matrix4::look_at(Point3::new(0.0, 1.0, -5.0), Point3::new(0.0, 1.0, 0.0), Vector3::new(0.0, -1.0, 0.0));
let trans_mat = Matrix4::from_translation(trans);
let rot_mat = Matrix4::from(rot);
builder = self.draw_node(node.index(), proj * view * trans_mat * rot_mat, viewport_dimensions, builder);

所以你可以看到,我将 proj * view * trans_mat * rot_mat 相乘...也许这是错误的顺序?

任何帮助将不胜感激。我没有很强的数学背景,并且多年来一直在尝试自己学习 CG,所以我不知道还能去哪里。一些关于此类内容的阅读资源也将不胜感激。

最佳答案

拉伸(stretch)的原因是我错误地组合了初始四元数和后续四元数。您不能只是将它们相加,但 * 运算符可以连接旋转。

所以我将代码的鼠标输入部分更改为此并且它有效:

let diff_x = position.0 - last_x;
if diff_x > 0.0 {
    // println!("turn right");
    let rotation_scalar = ((rotation_angle + rotation_speed) / 2.0 as f32).cos();
    let rotation_vec = Vector3::new(
        rotation_axis.x * ((rotation_angle + rotation_speed) / 2.0 as f32).sin(),
        rotation_axis.y * ((rotation_angle + rotation_speed) / 2.0 as f32).sin(),
        rotation_axis.z * ((rotation_angle + rotation_speed) / 2.0 as f32).sin());
    let rotation_quat2 = Quaternion::from_sv(rotation_scalar, rotation_vec);
    rotation_quat = rotation_quat * rotation_quat2;
} else if diff_x < 0.0 {
    // println!("turn left");
    let rotation_scalar = ((rotation_angle - rotation_speed) / 2.0 as f32).cos();
    let rotation_vec = Vector3::new(
        rotation_axis.x * ((rotation_angle - rotation_speed) / 2.0 as f32).sin(),
        rotation_axis.y * ((rotation_angle - rotation_speed) / 2.0 as f32).sin(),
        rotation_axis.z * ((rotation_angle - rotation_speed) / 2.0 as f32).sin());
    let rotation_quat2 = Quaternion::from_sv(rotation_scalar, rotation_vec);
    rotation_quat = rotation_quat * rotation_quat2;
}
last_x = position.0;

关于3d - 四元数旋转导致场景拉伸(stretch),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49342163/

相关文章:

javascript - 如何从 three.js 中的场景中删除所有 Mesh 对象?

rust - 使用公共(public)命名空间 quick_xml::se 时出错

math - 什么是SVD(奇异值分解)

math - 绕 Y 轴旋转

r - plotly 3d surface - 将立方体更改为矩形空间

java - Libgdx 近战攻击碰撞检测

openGL - 创建弯曲表面

rust - 为什么我们需要取消引用匹配中的可变引用来更改它?

rust - 了解在迭代器上调用方法两次时如何满足借用检查器?

c++ - 线性代数的CPU指令集?