Deriving transformation matrix in wgsl shader

1.3k Views Asked by At

Deriving the transformation matrix is a fairly common requirement for shaders. Are there and wgsl standard libraries for doing this sort of thing? i.e. even mat4x4 - mat4x4 multiplication would be useful!

I've written a rough draft below, but it seems like a fairly longwinded way of doing it

// Create a homogeneous transformation matrix from a translation vector.
fn mk_translation_matrix(v: vec3<f32>) -> mat4x4<f32>{
        let c_1: vec4<f32> = vec4<f32>(1., 0., 0., v.x);
        let c_2: vec4<f32> = vec4<f32>(0., 1., 0., v.y);
        let c_3: vec4<f32> = vec4<f32>(0., 0., 1., v.z);
        let c_4: vec4<f32> = vec4<f32>(0., 0., 0., 1.);
        let translation_matrix = mat4x4<f32>(c_1, c_2, c_3, c_4); 
        return translation_matrix; 
}

fn mk_rotation_matrix(q: vec4<f32>) -> mat4x4<f32> {
        let m11 = 2. * (q.x * q.x + q.y * q.y) - 1.; 
        let m12 = 2. * (q.y * q.z - q.x * q.w); 
        let m13 = 2. * (q.y * q.w - q.x * q.z);

        let m21 = 2. * (q.y * q.z + q.x * q.w);
        let m22 = 2. * (q.x * q.x + q.z * q.z) - 1.; 
        let m23 = 2. * (q.z * q.w + q.x * q.y); 

        let m31 = 2. * (q.y * q.w - q.x * q.z);
        let m32 = 2. * (q.z * q.w + q.x * q.y); 
        let m33 = 2. * (q.x * q.x + q.w * q.w) - 1.; 

        let c_1: vec4<f32> = vec4<f32>(m11, m21, m31, 0.);
        let c_2: vec4<f32> = vec4<f32>(m12, m22, m32, 0.);
        let c_3: vec4<f32> = vec4<f32>(m13, m23, m33, 0.);
        let c_4: vec4<f32> = vec4<f32>(0., 0., 0., 1.);


        let rotation_matrix: mat4x4<f32> = mat4x4<f32>(c_1, c_2, c_3, c_4); 
        return rotation_matrix; 
}


fn mat4_mul(A: mat4x4<f32>, B: mat4x4<f32> ) -> mat4x4<f32> {

        // rows of A
        let r_1: vec4<f32> =  transpose(A)[0]; 
        let r_2: vec4<f32> =  transpose(A)[1]; 
        let r_3: vec4<f32> =  transpose(A)[2]; 
        let r_4: vec4<f32> =  transpose(A)[3]; 
        //cols of B
        let c_1: vec4<f32> = B[0];
        let c_2: vec4<f32> = B[1];
        let c_3: vec4<f32> = B[2];
        let c_4: vec4<f32> = B[3];

        let multiplied = mat4x4<f32>(
            vec4<f32>(dot(r_1 , c_1), dot(r_2, c_1), dot(r_3, c_1), dot(c_4,c_1)),
            vec4<f32>(dot(r_1, c_2), dot(r_2, c_2), dot(r_3, c_2), dot(c_4, c_2)),
            vec4<f32>(dot(r_1, c_3), dot(r_2, c_3), dot(r_3, c_3), dot(c_4, c_3)),
            vec4<f32>(dot(r_1, c_4), dot(r_2, c_4), dot(r_3, c_4), dot(c_4, c_4)),
    );

        return multiplied; 

}

fn mk_transformation_matrix(position: vec3<f32>, rotation: vec4<f32>) -> mat4x4<f32> {
    let transformation_matrix = mat4_mul(mk_translation_matrix(position), mk_rotation_matrix(rotation)); 
    return transformation_matrix; 
}

1

There are 1 best solutions below

2
On BEST ANSWER

From the WGSL spec.

Multiplication (Section "Matrix arithmetic")

Transpose