NORMAL_MATRIX_WGSL:"fn normalMatrix(model : mat4x4<f32>) -> mat3x3<f32> {\n let a0 = model[0].xyz;\n let a1 = model[1].xyz;\n let a2 = model[2].xyz;\n let c0 = cross(a1, a2);\n let c1 = cross(a2, a0);\n let c2 = cross(a0, a1);\n return mat3x3<f32>(c0, c1, c2) * (1.0 / dot(a0, c0));\n}"
The inverse-transpose of the model matrix's upper 3×3, as WGSL — the
historical per-vertex cofactor form.
Cofactor form: with columns a₀ a₁ a₂, transpose(inverse(A)) has columns
a₁×a₂, a₂×a₀, a₀×a₁, all over det(A) = a₀·(a₁×a₂). Kept exported so
tests and docs that grep the name still find it; the live lit/standard
vertex stages read draw.normalMatrix, packed once per draw by
Matrix3.setNormalFromMatrix4 (the same inverse-transpose, and the same
identity-on-singular policy the math tests pin).
The inverse-transpose of the model matrix's upper 3×3, as WGSL — the historical per-vertex cofactor form.
Cofactor form: with columns
a₀ a₁ a₂,transpose(inverse(A))has columnsa₁×a₂, a₂×a₀, a₀×a₁, all overdet(A) = a₀·(a₁×a₂). Kept exported so tests and docs that grep the name still find it; the live lit/standard vertex stages readdraw.normalMatrix, packed once per draw byMatrix3.setNormalFromMatrix4(the same inverse-transpose, and the same identity-on-singular policy the math tests pin).