nightshade-renderer 0.57.0

GPU-driven wgpu renderer with a built-in frame graph.
//! Virtualized-geometry rendering from baked meshlet meshes: cull, rasterize,
//! resolve, inside one node.
//!
//! **Cull.** One compute thread per instance walks that instance's hierarchy
//! and emits the clusters that make up a single cut through it: a subtree whose
//! error already lands under a pixel is dropped because coarser geometry
//! covers it, and a cluster is kept only where its parent's error is too large
//! while its own is not. Those two tests bracket exactly one level per region,
//! which is what keeps levels from overlapping or leaving cracks between them.
//! Anything the frustum rejects costs one test rather than a walk. Each survivor
//! is then sorted into the rasterizer its size suits, and those counts become
//! the two draws.
//!
//! **Software raster.** One workgroup per small cluster, one thread per
//! triangle, each walking only the pixels it covers. A hardware rasterizer
//! shades in two by two quads whatever it draws, so a triangle covering one
//! pixel wastes three quarters of it, and a level of detail cut exists to make
//! triangles pixel-sized. Depth packed above the payload in a 64 bit value makes
//! one atomic max serve as the depth test, so this needs no attachment at all.
//! Where the device cannot do that, this path does not exist and everything goes
//! to hardware.
//!
//! **Hardware raster.** One indirect draw over the clusters too large for
//! compute, or crossing the near plane where clipping is needed, pulling
//! triangles straight from the shared streams with no vertex buffers. Each
//! covered pixel keeps only the cluster and triangle it landed on.
//!
//! **Resolve.** One fullscreen pass reads a pixel's cluster and triangle,
//! refetches those three vertices, recovers barycentrics from the clip
//! positions alone, and shades it from its material. Shading once per visible
//! pixel rather than once per covered fragment is the point of the visibility
//! buffer: overdraw costs an integer write instead of a material. It is also
//! where meshlet geometry is tested against the rest of the scene, since the
//! atomic settles meshlets against each other and nothing else.
//!
//! The cpu never iterates the scene. It uploads instances when they change,
//! reserves the cluster list, resets the draw and the dispatch, and issues them.
//!
//! Not here yet: shadows, clustered point lights and image based lighting in the
//! resolve, picking, occlusion culling against a depth pyramid, delta instance
//! uploads, and streaming.

mod node;
pub use node::MeshletPass;

mod scene;
mod types;
pub use types::{MESHLET_VISIBILITY_BUFFER_EMPTY, MeshletInstanceUniform};

/// The constants the shaders are compiled against, so the numbers the cpu sizes
/// the draw and the dispatch with are the same numbers the shaders pack and
/// unpack with.
pub fn meshlet_shader_defs() -> [(&'static str, naga_oil::compose::ShaderDefValue); 2] {
    [
        (
            "MESHLET_TRIANGLE_ID_BITS",
            naga_oil::compose::ShaderDefValue::UInt(types::MESHLET_TRIANGLE_ID_BITS),
        ),
        (
            "MESHLET_MAX_TRIANGLES",
            naga_oil::compose::ShaderDefValue::UInt(types::MESHLET_MAX_TRIANGLES),
        ),
    ]
}