nightshade-renderer 0.57.0

GPU-driven wgpu renderer with a built-in frame graph.
#define_import_path nightshade_renderer::meshlet_streams

#import nightshade_renderer::meshlet_data::{Meshlet, InstancedOffset, MeshletInstance, CENTIMETERS_PER_METER, octahedral_decode_signed}

/// The shared meshlet streams, and the decode that pulls vertices out of the
/// quantized bitstream by index.
///
/// Group one throughout, so a pass keeps group zero for what is its own. The
/// group is identical for both rasterizers and the resolve, so one layout and
/// one bind group serve all three. A pass that reads only some of these still
/// binds all of them.

@group(1) @binding(0) var<storage, read> raster_clusters: array<InstancedOffset>;
@group(1) @binding(1) var<storage, read> meshlets: array<Meshlet>;
@group(1) @binding(2) var<storage, read> meshlet_indices: array<u32>;
@group(1) @binding(3) var<storage, read> meshlet_vertex_positions: array<u32>;
@group(1) @binding(4) var<storage, read> meshlet_vertex_normals: array<u32>;
@group(1) @binding(5) var<storage, read> meshlet_vertex_uvs: array<vec2<f32>>;
@group(1) @binding(6) var<storage, read> meshlet_instances: array<MeshletInstance>;

fn get_meshlet_vertex_id(index_id: u32) -> u32 {
    let packed_index = meshlet_indices[index_id / 4u];
    let bit_offset = (index_id % 4u) * 8u;
    return extractBits(packed_index, bit_offset, 8u);
}

fn get_meshlet_vertex_position(meshlet: ptr<function, Meshlet>, vertex_id: u32) -> vec3<f32> {
    var bits_per_channel = vec3<u32>(
        extractBits((*meshlet).packed_bits, 0u, 8u),
        extractBits((*meshlet).packed_bits, 8u, 8u),
        extractBits((*meshlet).packed_bits, 16u, 8u),
    );
    let bits_per_vertex = bits_per_channel.x + bits_per_channel.y + bits_per_channel.z;
    var start_bit = (*meshlet).start_vertex_position_bit + (vertex_id * bits_per_vertex);

    var vertex_position_packed = vec3<u32>(0u);
    for (var channel = 0u; channel < 3u; channel++) {
        let lower_word_index = start_bit / 32u;
        let lower_word_bit_offset = start_bit & 31u;
        var next_32_bits = meshlet_vertex_positions[lower_word_index] >> lower_word_bit_offset;
        if lower_word_bit_offset + bits_per_channel[channel] > 32u {
            next_32_bits |= meshlet_vertex_positions[lower_word_index + 1u] << (32u - lower_word_bit_offset);
        }
        vertex_position_packed[channel] = extractBits(next_32_bits, 0u, bits_per_channel[channel]);
        start_bit += bits_per_channel[channel];
    }

    var vertex_position = vec3<f32>(vertex_position_packed) + vec3<f32>(
        (*meshlet).min_vertex_position_channel_x,
        (*meshlet).min_vertex_position_channel_y,
        (*meshlet).min_vertex_position_channel_z,
    );

    let quantization_factor = extractBits((*meshlet).packed_bits, 24u, 8u);
    vertex_position /= f32(1u << quantization_factor) * CENTIMETERS_PER_METER;

    return vertex_position;
}

fn get_meshlet_vertex_normal(meshlet: ptr<function, Meshlet>, vertex_id: u32) -> vec3<f32> {
    let packed_normal = meshlet_vertex_normals[(*meshlet).start_vertex_attribute_id + vertex_id];
    return octahedral_decode_signed(unpack2x16snorm(packed_normal));
}

fn get_meshlet_vertex_uv(meshlet: ptr<function, Meshlet>, vertex_id: u32) -> vec2<f32> {
    return meshlet_vertex_uvs[(*meshlet).start_vertex_attribute_id + vertex_id];
}