Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Skeletal Meshes

SkinnedVertex

SkinnedVertex is Vertex’s 4 fields (position, UV, normal, tangent) plus per-vertex skinning data — up to 4 joint indices and matching weights:

use pebble::wgpu::skinned_mesh::SkinnedVertex;

let v = SkinnedVertex::new(
    glam::Vec3::new(0.0, 0.6, 0.0),
    glam::Vec2::ZERO,
    glam::Vec3::Z,
    glam::Vec4::new(1.0, 0.0, 0.0, 1.0),
    [0, 1, 0, 0],        // joint_indices — up to 4 joints this vertex is bound to
    [0.7, 0.3, 0.0, 0.0], // joint_weights — matching weights, usually summing to ~1.0
);

joint_indices is [u16; 4] — glTF’s own JOINTS_n accessor is spec-limited to 8/16-bit indices, so u16 already covers every legal glTF skeleton losslessly, at half the bytes of u32.

SkinnedVertex::layout() occupies vertex buffer locations 0–3 (same meaning as Vertex’s own 0–3) and 8–9 — deliberately skipping 4–7, which InstanceVertex uses, so a skinned mesh can still be paired with per-instance data in one pipeline without either layout changing. On the WGSL side, declare @location(8) joint_indices: vec4<u32> and @location(9) joint_weights: vec4<f32> — every integer vertex format widens to vec4<u32> in the shader regardless of the source width.

Building a skinned mesh

SkinnedMesh is plain data with no public constructors of its own — the only way to build one is SkinnedMeshBuilder, same shape as MeshBuilder:

use pebble::wgpu::skinned_mesh::SkinnedMeshBuilder;

let mesh = SkinnedMeshBuilder::new(vertices, indices).build_asset("character", &mut skinned_meshes);

.build_asset returns a Handle<SkinnedMesh>, uploaded automatically through the same asset pipeline as every other GPU resource. Assets<SkinnedMesh>::get(handle) returns Option<&GPUSkinnedMesh>vertex_buffer/index_buffer/index_count, exactly like GPUMesh.

In practice you’ll rarely hand-author SkinnedVertex data yourself — use SkinnedMeshBuilder::from_file to load a glTF file and get back a LoadedSkinnedMesh (mesh handles + a ready AnimationPlayer) in one call. See Skeletons and Animation for the full rendering loop.