I then feed these a quaternion that rotates around the Y axis t / 10000 radians (t = time):
The result surprises me because my model is rotating counter-clockwise but I expected it to rotate clockwise, since the angle is increasing (checked it, quat's xyz increase with time). Rotation around the X or Z axes is also backwards.
All translations as well as matrix rotations work as expected in my coordinate system. I suspect my formulas are wrong, and probably assume +Z is forward. If I transpose my model matrix (or post-multiply with it) it rotates as expected, which suggests it's a handedness problem.
toMat4(dest = new Mat4()): Mat4 {
const { x, y, z, w } = this
const x2 = x + x
const y2 = y + y
const z2 = z + z
const xx = x * x2
const xy = x * y2
const xz = x * z2
const yy = y * y2
const yz = y * z2
const zz = z * z2
const wx = w * x2
const wy = w * y2
const wz = w * z2
// Notice matrix is column-major
// Source:
// https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#Quaternion-derived_rotation_matrix
dest.init([
1 - (yy + zz), xy - wz, xz + wy, 0,
xy + wz, 1 - (xx + zz), yz - wx, 0,
xz - wy, yz + wx, 1 - (xx + yy), 0,
0, 0, 0, 1,
])
return dest
}
precision mediump float;
attribute vec3 aVertexPosition;
attribute vec2 aVertexUV;
struct Transform {
float scale;
vec3 translation;
vec4 rotation;
};
uniform Transform uModel;
uniform Transform uView;
uniform mat4 uProjection;
varying vec2 vUV;
// Source:
// https://twistedpairdevelopment.wordpress.com/2013/02/11/rotating-a-vector-by-a-quaternion-in-glsl/
vec3 rotateVector(vec4 quat, vec3 vec) {
return vec + 2.0 * cross(cross(vec, quat.xyz) + quat.w * vec, quat.xyz);
}
void main(void) {
vUV = aVertexUV;
vec3 world = rotateVector(uModel.rotation, aVertexPosition * uModel.scale) + uModel.translation;
vec3 view = rotateVector(uView.rotation, world * uView.scale) + uView.translation;
gl_Position = uProjection * vec4(view, 1.0);
}