Vectors, Matrices & Swizzling

Swizzle sets: xyzw or rgba (don't mix within one swizzle).

8.1 Construction & swizzles

Swizzle sets: xyzw or rgba (don't mix within one swizzle).

float4 v = float4(1, 2, 3, 4);
float3 a = float3(v.xy, 5);        // (1, 2, 5)
float4 b = float4(a, 1);
float2 c = v.zw;                   // (3, 4)
float4 d = v.wzyx;                 // reversed
float3 e = v.rrr;                  // color names: r g b a
v.xy = float2(0, 0);               // write mask
// v.xx = 1;                       // error: duplicate components in an l-value
float  s = v[2];                   // indexing → 3

8.2 Component-wise arithmetic

float3 p = float3(1, 2, 3), q = float3(4, 5, 6);
float3 sum  = p + q;               // (5, 7, 9)
float3 prod = p * q;               // (4, 10, 18) — component-wise!
float3 sc   = p * 2.0;             // scalar broadcast
bool3  lt   = p < q;               // component-wise comparison → bool3
bool   allLt = all(p < q);
float  d    = dot(p, q);           // 32
float3 x    = cross(p, q);         // (-3, 6, -3)

8.3 Matrices

HLSL has no inverse() intrinsic. Compute inverses on the CPU (DirectXMath XMMatrixInverse) and upload them, or write your own adjugate-based function.

float4x4 M = {
    1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 0,
    5, 6, 7, 1     // fourth ROW
};
float  m23 = M[1][2];       // row 1, column 2 (zero-based)
float4 row = M[3];          // (5, 6, 7, 1)
float  e   = M._m31;        // zero-based member: row 3, column 1 → 6
float  e1  = M._42;         // one-based member: row 4, column 2 → 6

float4 v  = float4(1, 1, 1, 1);
float4 r1 = mul(v, M);      // row vector × matrix (v treated as 1×4)
float4 r2 = mul(M, v);      // matrix × column vector (v treated as 4×1)
float4x4 C = mul(A, B);     // matrix product
float4x4 W = A * B;         // component-wise product — NOT matrix multiplication!
float4x4 T = transpose(M);
float    det = determinant(M);
float3x3 R = (float3x3)M;   // upper-left 3×3

8.4 Row-major vs column-major (the #1 source of confusion)

Two independent things:

Math convention — row vectors mul(v, M) (classic D3DX/DirectXMath style: v * World * View * Proj) vs column vectors mul(M, v). mul(v, M) == mul(transpose(M), v).

Memory packing — how matrices are stored in cbuffers. HLSL's default is column_major packing (each register holds a column), while DirectXMath stores row-major in memory.

DirectXMath, no transpose on upload default (column_major) mul(M, v) (the matrix appears transposed, which flips the convention)

DirectXMath, XMMatrixTranspose before upload mul(v, M) — the classic D3D sample convention DirectXMath, no transpose row_major float4x4 M; or -Zpr GLM (column-major, column vectors)

Pick one convention for the whole project and document it. Control packing with row_major/column_major keywords, #pragma pack_matrix(row_major), or dxc -Zpr / -Zpc.