3d 四元数旋转导致场景拉伸

3d 四元数旋转导致场景拉伸,3d,rust,linear-algebra,quaternions,3d,Rust,Linear Algebra,Quaternions,我已经修改了一个,允许键盘和鼠标输入,将平移和旋转应用到场景中。平移效果很好,但旋转会导致场景中的对象向上移动到摄影机并拉伸,直到它们看起来像垃圾,因为旋转接近90-180度 这是旋转前场景的外观: 当旋转角度约为90度时: 我用它来旋转。我以前没有使用过四元数,所以我想知道是否有人能告诉我是否正确使用了四元数,我怀疑这就是问题所在 这就是我创建初始四元数的方法,使用我找到的方程: 然后我修改四元数,对鼠标输入应用旋转,如下所示: let diff_x = position.0 - last

我已经修改了一个,允许键盘和鼠标输入,将平移和旋转应用到场景中。平移效果很好,但旋转会导致场景中的对象向上移动到摄影机并拉伸,直到它们看起来像垃圾,因为旋转接近90-180度

这是旋转前场景的外观:

当旋转角度约为90度时:

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

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

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

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\u mat*rot\u mat。。。也许那是错误的顺序


任何帮助都将不胜感激。我没有很强的数学背景,多年来我一直在努力自学CG,所以我不知道还能去哪里。一些关于这类东西的阅读资料也会很受欢迎。

拉伸的原因是因为我错误地组合了最初的四元数和随后的四元数。不能只将它们添加在一起,但*操作符可以连接旋转

因此,我将代码的鼠标输入部分更改为以下内容:

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;
让diff_x=position.0-last_x;
如果差值x>0.0{
//println!(“右转”);
设旋转标量=((旋转角度+旋转速度)/2.0为f32.cos();
让旋转_vec=Vector3::新建(
旋转轴x*((旋转角度+旋转速度)/2.0,如f32)。sin(),
旋转轴y*((旋转角度+旋转速度)/2.0,如f32)。sin(),
旋转轴z*((旋转角度+旋转速度)/2.0,如f32.sin());
设rotation_quat2=四元数::from_sv(rotation_scalar,rotation_vec);
旋转量=旋转量*旋转量2;
}否则,如果差值x<0.0{
//println!(“左转”);
设旋转标量=((旋转角度-旋转速度)/2.0为f32.cos();
让旋转_vec=Vector3::新建(
旋转轴x*((旋转角度-旋转速度)/2.0,如f32).sin(),
旋转轴y*((旋转角度-旋转速度)/2.0,如f32).sin(),
旋转轴z*((旋转角度-旋转速度)/2.0,如f32.sin());
设rotation_quat2=四元数::from_sv(rotation_scalar,rotation_vec);
旋转量=旋转量*旋转量2;
}
last_x=位置0;
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;