scena 1.7.2

A Rust-native scene-graph renderer with typed scene state, glTF assets, and explicit prepare/render lifecycles.
Documentation
struct QuadVertex {
    @location(0) side_along: vec2<f32>,
};

struct StrokeInstance {
    @location(1) start: vec3<f32>,
    @location(2) end: vec3<f32>,
    @location(3) color: vec4<f32>,
    @location(4) width_px: f32,
};

struct VertexOut {
    @builtin(position) position: vec4<f32>,
    @location(0) color: vec4<f32>,
    @location(1) distance_px: f32,
    @location(2) half_width_px: f32,
};

struct LightingUniform {
    directional_light_direction_intensity: array<vec4<f32>, 16>,
    directional_light_color: array<vec4<f32>, 16>,
    directional_shadow_control: array<vec4<f32>, 16>,
    point_light_position_intensity: array<vec4<f32>, 16>,
    point_light_color_range: array<vec4<f32>, 16>,
    spot_light_position_intensity: array<vec4<f32>, 16>,
    spot_light_direction_cones: array<vec4<f32>, 16>,
    spot_light_cone_range: array<vec4<f32>, 16>,
    spot_light_color_range: array<vec4<f32>, 16>,
    area_light_position_flux: array<vec4<f32>, 2>,
    area_light_axis_x_shape: array<vec4<f32>, 2>,
    area_light_axis_y_range: array<vec4<f32>, 2>,
    area_light_color: array<vec4<f32>, 2>,
    light_counts: vec4<f32>,
    environment_diffuse_intensity: vec4<f32>,
    environment_specular_intensity: vec4<f32>,
};

struct CameraUniform {
    view_from_world: mat4x4<f32>,
    clip_from_view: mat4x4<f32>,
    clip_from_world: mat4x4<f32>,
    light_from_world: mat4x4<f32>,
    camera_position_exposure: vec4<f32>,
    viewport_near_far: vec4<f32>,
    color_management: vec4<f32>,
    lighting: LightingUniform,
};

struct DrawUniform {
    world_from_model: mat4x4<f32>,
    normal_from_model: mat4x4<f32>,
    tint: vec4<f32>,
};

struct ClippedSegment {
    start: vec4<f32>,
    end: vec4<f32>,
    visible: f32,
};

const STROKE_AA_RADIUS_PX: f32 = 3.25;

@group(0) @binding(0)
var<uniform> camera: CameraUniform;

@group(2) @binding(0)
var<uniform> draw: DrawUniform;

@vertex
fn vs_main(quad: QuadVertex, segment: StrokeInstance) -> VertexOut {
    let start_world = draw.world_from_model * vec4<f32>(segment.start, 1.0);
    let end_world = draw.world_from_model * vec4<f32>(segment.end, 1.0);
    let clipped = clip_segment_to_near(
        camera.clip_from_world * start_world,
        camera.clip_from_world * end_world,
    );
    let start_ndc = clipped.start.xy / max(clipped.start.w, 0.0001);
    let end_ndc = clipped.end.xy / max(clipped.end.w, 0.0001);
    let delta = end_ndc - start_ndc;
    let length_px = length(delta * camera.viewport_near_far.xy * 0.5);
    let direction = select(vec2<f32>(1.0, 0.0), normalize(delta), length_px > 0.001);
    let normal = vec2<f32>(-direction.y, direction.x);
    let half_width = max(segment.width_px, 0.001) * 0.5;
    let aa_radius = STROKE_AA_RADIUS_PX;
    let expanded_half_width = half_width + aa_radius;
    let offset_ndc = normal * quad.side_along.x * expanded_half_width * vec2<f32>(
        2.0 / max(camera.viewport_near_far.x, 1.0),
        2.0 / max(camera.viewport_near_far.y, 1.0),
    );
    var position = select(clipped.start, clipped.end, quad.side_along.y > 0.5);
    position.x = position.x + offset_ndc.x * position.w;
    position.y = position.y + offset_ndc.y * position.w;
    if clipped.visible < 0.5 || length_px <= 0.001 {
        position = vec4<f32>(2.0, 2.0, 0.0, 1.0);
    }
    var out: VertexOut;
    out.position = position;
    out.color = segment.color * draw.tint;
    out.distance_px = quad.side_along.x * expanded_half_width;
    out.half_width_px = half_width;
    return out;
}

@fragment
fn fs_main(in: VertexOut) -> @location(0) vec4<f32> {
    let coverage = stroke_coverage(abs(in.distance_px), in.half_width_px);
    if coverage <= 0.0 {
        discard;
    }
    return vec4<f32>(clamp(in.color.rgb, vec3<f32>(0.0), vec3<f32>(1.0)), in.color.a * coverage);
}

fn stroke_coverage(distance_px: f32, half_width_px: f32) -> f32 {
    if distance_px <= half_width_px {
        return 1.0;
    }
    let t = clamp((distance_px - half_width_px) / STROKE_AA_RADIUS_PX, 0.0, 1.0);
    return 1.0 - t * t * (3.0 - 2.0 * t);
}

fn clip_segment_to_near(start: vec4<f32>, end: vec4<f32>) -> ClippedSegment {
    var a = start;
    var b = end;
    if a.z < 0.0 && b.z < 0.0 {
        return ClippedSegment(a, b, 0.0);
    }
    if a.z < 0.0 {
        let t = clamp((0.0 - a.z) / max(b.z - a.z, 0.000001), 0.0, 1.0);
        a = mix(a, b, t);
    }
    if b.z < 0.0 {
        let t = clamp((0.0 - b.z) / max(a.z - b.z, 0.000001), 0.0, 1.0);
        b = mix(b, a, t);
    }
    return ClippedSegment(a, b, 1.0);
}