Matrices are column-major. m11 is column 0, row 0. .v[] is that same
order. Products are AB, so (AB)v == A(Bv) with the column vector on the
right.
matrix3 ident = {
.m11 = 1.0f, .m21 = 0.0f, .m31 = 0.0f,
.m12 = 0.0f, .m22 = 1.0f, .m32 = 0.0f,
.m13 = 0.0f, .m23 = 0.0f, .m33 = 1.0f
};
matrix3 also = { .v = {1, 0, 0, 0, 1, 0, 0, 0, 1} };
for (int i = 0; i < 9; i++)
also.v[i] *= 2.0f;The named form of a 3×3 determinant matches the column-major fields:
float determinant(const matrix3 *mat)
{
return mat->m11 * (mat->m22 * mat->m33 - mat->m23 * mat->m32)
- mat->m12 * (mat->m21 * mat->m33 - mat->m23 * mat->m31)
+ mat->m13 * (mat->m21 * mat->m32 - mat->m22 * mat->m31);
}mat3_mul is that product. The loop is the same layout, written out:
void multiply(matrix3 *result, const matrix3 *a, const matrix3 *b)
{
for (int c = 0; c < 3; c++) { /* columns of result / of B */
for (int r = 0; r < 3; r++) { /* rows of result / of A */
float sum = 0.0f;
for (int k = 0; k < 3; k++)
sum += a->v[k * 3 + r] * b->v[c * 3 + k];
result->v[c * 3 + r] = sum;
}
}
}A 4×4 that applies a 3×3 and then a translation is [A t; 0 1].
mat4_from_mat3 copies A and leaves the translation at zero. The fourth
column is t.
void affine_matrix(matrix4 *out, const matrix3 *linear, const vector3 *translation)
{
*out = mat4_from_mat3(*linear);
out->m14 = translation->x;
out->m24 = translation->y;
out->m34 = translation->z;
out->m44 = 1.0f;
}The same matrix from translation, rotation, and scale, which is the usual model matrix:
const quaternion rot = quat_from_euler_deg(vec3(0.0f, 90.0f, 0.0f));
const matrix4 model = mat4_trs(vec3(1.0f, 0.0f, 2.0f), rot, vec3(2.0f, 2.0f, 2.0f));
const matrix4 inverse = mat4_inverse_affine(model);
const matrix4 normal = mat4_normal(model);mat4_inverse_affine is the inverse of an [A t; 0 1] transform.
mat4_normal is the inverse-transpose of the 3×3, for normals.
View, then projection. mat4_mul(proj, view) applies the view first.
Clip helpers select handedness and depth range; the *_rh / *_zo names
are the fixed ones.
const matrix4 view = mat4_look_at_rh(vec3(0.0f, 2.0f, 6.0f),
vec3_zero(),
vec3(0.0f, 1.0f, 0.0f));
const matrix4 proj = mat4_perspective_rh_no(VM_DEG(70.0), 1.777f, 0.05f, 500.0f);
const matrix4 clip_from_world = mat4_mul(proj, view);
const vector4 clip = mat4_mul_vec4(clip_from_world, vec4(0.0f, 1.0f, 0.0f, 1.0f));A fly camera has a direction instead of a target:
const vector3 forward = vec3_normalize(vec3(0.0f, 0.0f, -1.0f));
const matrix4 fly = mat4_look_from_dir_rh(vec3(0.0f, 1.6f, 0.0f),
forward,
vec3(0.0f, 1.0f, 0.0f));