# Quaternion rotation is inverse of what I expect

I'm trying to learn quaternions and decided to implement my own quaternion class.

To test it I made a couple vertex shaders, one that gets a model matrix (calculated from the quaternion) and another that gets the rotation quaternion directly and rotates vertices in-shader.

I then feed these a quaternion that rotates around the Y axis t / 10000 radians (t = time):

const rotation = Quat.fromAxisAngle(new Vec3([0, 1, 0]), t / 10000)


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.

Where are my formulas wrong and how can I understand the math behind this?

### Details

• My matrices are column-major in memory (to match GLSL's mat4).
• My coordinate system is +X right, +Y up, -Z forward.

## My code

### Quaternion from axis + angle

function fromAxisAngle(axis: Vec3, angle: number, dest = new Quat()): Quat {
angle *= 0.5
const sin = Math.sin(angle)

dest.x = axis.x * sin
dest.y = axis.y * sin
dest.z = axis.z * sin
dest.w = Math.cos(angle)

return dest
}


Note: I noticed if I negate this quaternion's x, y and z, everthing works as expected. Is this the root cause? I thought quaternions didn't have handedness!

Since this is actually just inverting the quaternion (and thus its rotation) I'm afraid I'm just patching over the root cause. I don't want to patch the issue, I want to fix my math!

### Matrix from quaternion

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;

uniform mat4 uModelMatrix;
uniform mat4 uViewMatrix;
uniform mat4 uProjectionMatrix;

varying vec2 vUV;

void main(void) {
vUV = aVertexUV;

gl_Position = uProjectionMatrix * uViewMatrix * uModelMatrix * vec4(aVertexPosition.xyz, 1.0);
}


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);
}