pub const KERNEL_SKINNING: &str = r#"
// GPU skinning kernel
// Transforms vertices by a weighted sum of bone matrices.
layout(local_size_x = 256) in;
struct Vertex {
vec4 position; // xyz = position, w = 1
vec4 normal; // xyz = normal, w = 0
vec4 tangent; // xyz = tangent, w = handedness
vec4 bone_weights; // up to 4 bone weights
uvec4 bone_indices; // up to 4 bone indices
};
struct SkinnedVertex {
vec4 position;
vec4 normal;
vec4 tangent;
vec4 _reserved;
};
layout(std430, binding = 0) readonly buffer VerticesIn {
Vertex vertices_in[];
};
layout(std430, binding = 1) writeonly buffer VerticesOut {
SkinnedVertex vertices_out[];
};
layout(std430, binding = 2) readonly buffer BoneMatrices {
mat4 bones[];
};
layout(std430, binding = 3) readonly buffer InverseBindMatrices {
mat4 inv_bind[];
};
uniform uint u_vertex_count;
uniform uint u_bone_count;
uniform uint u_max_bones_per_vertex;
mat4 get_skin_matrix(uvec4 indices, vec4 weights) {
mat4 skin = mat4(0.0);
// Bone 0
if (weights.x > 0.0 && indices.x < u_bone_count) {
skin += weights.x * (bones[indices.x] * inv_bind[indices.x]);
}
// Bone 1
if (u_max_bones_per_vertex > 1u && weights.y > 0.0 && indices.y < u_bone_count) {
skin += weights.y * (bones[indices.y] * inv_bind[indices.y]);
}
// Bone 2
if (u_max_bones_per_vertex > 2u && weights.z > 0.0 && indices.z < u_bone_count) {
skin += weights.z * (bones[indices.z] * inv_bind[indices.z]);
}
// Bone 3
if (u_max_bones_per_vertex > 3u && weights.w > 0.0 && indices.w < u_bone_count) {
skin += weights.w * (bones[indices.w] * inv_bind[indices.w]);
}
return skin;
}
void main() {
uint idx = gl_GlobalInvocationID.x;
if (idx >= u_vertex_count) return;
Vertex v = vertices_in[idx];
mat4 skin = get_skin_matrix(v.bone_indices, v.bone_weights);
// If no bones affect this vertex, use identity
if (v.bone_weights.x + v.bone_weights.y + v.bone_weights.z + v.bone_weights.w < 0.001) {
skin = mat4(1.0);
}
vec4 skinned_pos = skin * v.position;
vec3 skinned_normal = normalize(mat3(skin) * v.normal.xyz);
vec3 skinned_tangent = normalize(mat3(skin) * v.tangent.xyz);
vertices_out[idx].position = skinned_pos;
vertices_out[idx].normal = vec4(skinned_normal, 0.0);
vertices_out[idx].tangent = vec4(skinned_tangent, v.tangent.w);
}
"#;Expand description
Skeletal skinning kernel: apply bone matrix palette transforms.