# Quarternion rotation flattening cube

I am trying to rotate a cube using a quaternion matrix with WGPU. However, whenever I try to rotate it, I end up with

I am using the matrix from https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation. I have also tried multiplying the matrix and the vector in the wrong order, which in some occasions, results in something looking like a cube, but with a corner oddly stretched out.

fn vs_main(
model: VertexInput,
entity: EntityInput,
) -> VertexOutput {

let rotation = mat4x4<f32> (
vec4<f32>(entity.rotation_one, 0.0),
vec4<f32>(entity.rotation_two, 0.0),
vec4<f32>(entity.rotation_three, 0.0),
vec4<f32>(0.0,0.0,0.0,1.0),
);
let translation = mat4x4<f32> (
vec4<f32>(1.0,0.0,0.0,0.0),
vec4<f32>(0.0,1.0,0.0,0.0),
vec4<f32>(0.0,0.0,1.0,0.0),
vec4<f32>(0.0,0.0,5.0,1.0),
);
let transformation = translation * rotation;
var out: VertexOutput;
out.tex_pos = model.tex_pos;
out.clip_position = camera_mat * transformation * vec4<f32>(model.position, 1.0);
return out;
}


and the rotation matrix I am using is

        let w = (self.angle.to_f32().unwrap().to_radians() / 2.0).cos();
let x = self.axis.x.to_f32().unwrap() * (angle / 2.0).sin();
let y = self.axis.y.to_f32().unwrap() * (angle / 2.0).sin();
let z = self.axis.z.to_f32().unwrap() * (angle / 2.0).sin();
// https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation
[
[
w.powi(2) + x.powi(2) - y.powi(2) - z.powi(2),
2.0 * x * y + 2.0 * w * z,
2.0 * x * z - 2.0 * w * y,
],
[
2.0 * x * y - 2.0 * w * z,
w.powi(2) - x.powi(2) + y.powi(2) - z.powi(2),
2.0 * y * z + 2.0 * w * x,
],
[
2.0 * x * z + 2.0 * w * y,
2.0 * y * z - 2.0 * w * x,
w.powi(2) - x.powi(2) - y.powi(2) + z.powi(2),
],
]


The WGSL shader code is column-major.

EDIT: I have corrected the mistakes in my matrix as pointed out by ratchet freak.

• Is the object flattened immediately, or does it distort over a series of incremental rotations until it becomes completely flat? If the latter, this can be due to compounding rounding errors when you use an already-transformed vector or matrix as the input to compute the next incremental transformation. A small error can snowball and amplify with each iteration until you get to a singular case like this. Commented Aug 23, 2023 at 16:05
• It flattens immediately. Commented Aug 23, 2023 at 16:16

a in the formula under "From a quaternion to an orthogonal matrix" isn't the angle, it is the real or the w component of the quaternion. The value of which should be cos(angle/2).

and you are not consistent whether to convert to radians.

let w = (self.angle.to_f32().unwrap().to_radians() / 2.0).cos();
let x = self.axis.x.to_f32().unwrap() * (self.angle.to_f32().unwrap().to_radians()/ 2.0).sin();
let y = self.axis.y.to_f32().unwrap() * (self.angle.to_f32().unwrap().to_radians()/ 2.0).sin();
let z = self.axis.z.to_f32().unwrap() * (self.angle.to_f32().unwrap().to_radians()/ 2.0).sin();


and then replace angle with w in the computation of the matrix.

• Thank you. My conversion to radians is consistent, however, as you pointed out, I had misused w as the angle, and I have corrected this. However, the same symptoms are still displayed. Commented Aug 23, 2023 at 15:49

I resolved the issue, it turns out then when I was defining the descriptor for the vertex buffer layout, I miscalculated the memory locations, and thus a column of the rotation matrix was being excluded.