awsm-renderer 0.4.0

awsm-renderer
Documentation
//***** SKINS *****

// Each skin set has 8 f32 values (4 interleaved index/weight pairs)
const floats_per_set = 8u;

/// Applies skeletal skinning with support for multiple skin sets per vertex
fn apply_position_skin(input: ApplyVertexInput) -> ApplyVertexInput {
    var output = input;

    let skin_sets_count = geometry_mesh_meta.skin_sets_len;

    let original_position = vec4<f32>(input.position, 1.0);

    // Calculate base offset for this vertex's skin data (indexed per original vertex)
    let base_offset = (geometry_mesh_meta.skin_index_weights_offset / 4) + input.vertex_index * skin_sets_count * floats_per_set;

    let matrix_offset = geometry_mesh_meta.skin_matrices_offset / 64; // mat4x4<f32> is 64 bytes

    var skin_matrix: mat4x4<f32>;

    // UNROLLED SKIN SETS

    {% for i in 0..max_skin_unroll %}
        if skin_sets_count >= {{ i + 1}}u {
            let buffer_offset = base_offset + ({{ i }}u * floats_per_set);

            let joint_index_0 = bitcast<u32>(skin_joint_index_weights[buffer_offset]);
            let joint_weight_0 = skin_joint_index_weights[buffer_offset + 1u];

            let joint_index_1 = bitcast<u32>(skin_joint_index_weights[buffer_offset + 2u]);
            let joint_weight_1 = skin_joint_index_weights[buffer_offset + 3u];

            let joint_index_2 = bitcast<u32>(skin_joint_index_weights[buffer_offset + 4u]);
            let joint_weight_2 = skin_joint_index_weights[buffer_offset + 5u];

            let joint_index_3 = bitcast<u32>(skin_joint_index_weights[buffer_offset + 6u]);
            let joint_weight_3 = skin_joint_index_weights[buffer_offset + 7u];

            let skin_mat_acc = joint_weight_0 * skin_joint_matrices[joint_index_0 + matrix_offset]
                            + joint_weight_1 * skin_joint_matrices[joint_index_1 + matrix_offset]
                            + joint_weight_2 * skin_joint_matrices[joint_index_2 + matrix_offset]
                            + joint_weight_3 * skin_joint_matrices[joint_index_3 + matrix_offset];

            {% if i == 0 %}
                skin_matrix = skin_mat_acc;
            {% else %}
                skin_matrix = skin_matrix + skin_mat_acc;
            {% endif %}
        }
    {% endfor %}

    // LOOP FOR REMAINING SKIN SETS
    if skin_sets_count > {{ max_skin_unroll }}u {
        for (var skin_set_index = {{ max_skin_unroll }}u; skin_set_index < skin_sets_count; skin_set_index = skin_set_index + 1u) {
            let buffer_offset = base_offset + (skin_set_index * floats_per_set);

            let joint_index_0 = bitcast<u32>(skin_joint_index_weights[buffer_offset]);
            let joint_weight_0 = skin_joint_index_weights[buffer_offset + 1u];

            let joint_index_1 = bitcast<u32>(skin_joint_index_weights[buffer_offset + 2u]);
            let joint_weight_1 = skin_joint_index_weights[buffer_offset + 3u];

            let joint_index_2 = bitcast<u32>(skin_joint_index_weights[buffer_offset + 4u]);
            let joint_weight_2 = skin_joint_index_weights[buffer_offset + 5u];

            let joint_index_3 = bitcast<u32>(skin_joint_index_weights[buffer_offset + 6u]);
            let joint_weight_3 = skin_joint_index_weights[buffer_offset + 7u];

            let skin_mat_acc = joint_weight_0 * skin_joint_matrices[joint_index_0 + matrix_offset]
                             + joint_weight_1 * skin_joint_matrices[joint_index_1 + matrix_offset]
                             + joint_weight_2 * skin_joint_matrices[joint_index_2 + matrix_offset]
                             + joint_weight_3 * skin_joint_matrices[joint_index_3 + matrix_offset];

            skin_matrix = skin_matrix + skin_mat_acc;
        }
    }

    output.position = (skin_matrix * original_position).xyz;

    return output;
}

/// Applies skeletal skinning to normals and tangents (same weights as positions)
fn apply_normal_skin(input: ApplyVertexInput, normal: vec3<f32>) -> vec3<f32> {
    let skin_sets_count = geometry_mesh_meta.skin_sets_len;

    // Calculate base offset for this vertex's skin data (indexed per original vertex)
    let base_offset = (geometry_mesh_meta.skin_index_weights_offset / 4) + input.vertex_index * skin_sets_count * floats_per_set;
    let matrix_offset = geometry_mesh_meta.skin_matrices_offset / 64; // mat4x4<f32> is 64 bytes

    var skin_matrix: mat4x4<f32>;

    // UNROLLED SKIN SETS
    {% for i in 0..max_skin_unroll %}
        if skin_sets_count >= {{ i + 1}}u {
            let buffer_offset = base_offset + ({{ i }}u * floats_per_set);

            let joint_index_0 = bitcast<u32>(skin_joint_index_weights[buffer_offset]);
            let joint_weight_0 = skin_joint_index_weights[buffer_offset + 1u];

            let joint_index_1 = bitcast<u32>(skin_joint_index_weights[buffer_offset + 2u]);
            let joint_weight_1 = skin_joint_index_weights[buffer_offset + 3u];

            let joint_index_2 = bitcast<u32>(skin_joint_index_weights[buffer_offset + 4u]);
            let joint_weight_2 = skin_joint_index_weights[buffer_offset + 5u];

            let joint_index_3 = bitcast<u32>(skin_joint_index_weights[buffer_offset + 6u]);
            let joint_weight_3 = skin_joint_index_weights[buffer_offset + 7u];

            let skin_mat_acc = joint_weight_0 * skin_joint_matrices[joint_index_0 + matrix_offset]
                            + joint_weight_1 * skin_joint_matrices[joint_index_1 + matrix_offset]
                            + joint_weight_2 * skin_joint_matrices[joint_index_2 + matrix_offset]
                            + joint_weight_3 * skin_joint_matrices[joint_index_3 + matrix_offset];

            {% if i == 0 %}
                skin_matrix = skin_mat_acc;
            {% else %}
                skin_matrix = skin_matrix + skin_mat_acc;
            {% endif %}
        }
    {% endfor %}

    // LOOP FOR REMAINING SKIN SETS
    if skin_sets_count > {{ max_skin_unroll }}u {
        for (var skin_set_index = {{ max_skin_unroll }}u; skin_set_index < skin_sets_count; skin_set_index = skin_set_index + 1u) {
            let buffer_offset = base_offset + (skin_set_index * floats_per_set);

            let joint_index_0 = bitcast<u32>(skin_joint_index_weights[buffer_offset]);
            let joint_weight_0 = skin_joint_index_weights[buffer_offset + 1u];

            let joint_index_1 = bitcast<u32>(skin_joint_index_weights[buffer_offset + 2u]);
            let joint_weight_1 = skin_joint_index_weights[buffer_offset + 3u];

            let joint_index_2 = bitcast<u32>(skin_joint_index_weights[buffer_offset + 4u]);
            let joint_weight_2 = skin_joint_index_weights[buffer_offset + 5u];

            let joint_index_3 = bitcast<u32>(skin_joint_index_weights[buffer_offset + 6u]);
            let joint_weight_3 = skin_joint_index_weights[buffer_offset + 7u];

            let skin_mat_acc = joint_weight_0 * skin_joint_matrices[joint_index_0 + matrix_offset]
                             + joint_weight_1 * skin_joint_matrices[joint_index_1 + matrix_offset]
                             + joint_weight_2 * skin_joint_matrices[joint_index_2 + matrix_offset]
                             + joint_weight_3 * skin_joint_matrices[joint_index_3 + matrix_offset];

            skin_matrix = skin_matrix + skin_mat_acc;
        }
    }

    // Transform normal (use mat3 to ignore translation)
    let normal_matrix = mat3x3<f32>(
        skin_matrix[0].xyz,
        skin_matrix[1].xyz,
        skin_matrix[2].xyz
    );

    return normal_matrix * normal;
}