Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/facett

facett-core/src/render/gpu/scene3d.wgsl

// Scene3D — flat quads, screen-width line ribbons and SDF text glyphs on world
// planes, under one view-projection, depth-tested (render::gpu::scene3d).

struct Uniforms {
    view_proj: mat4x4<f32>,
    // xy = target size in physical px
    viewport: vec4<f32>,
};

@group(0) @binding(0) var<uniform> u: Uniforms;
@group(0) @binding(1) var atlas: texture_2d<f32>;
@group(0) @binding(2) var atlas_smp: sampler;

// ---------------------------------------------------------------- solid (quads)

struct SolidOut {
    @builtin(position) clip: vec4<f32>,
    @location(0) color: vec4<f32>,
};

@vertex
fn solid_vs(@location(0) pos: vec3<f32>, @location(1) color: vec4<f32>) -> SolidOut {
    var o: SolidOut;
    o.clip = u.view_proj * vec4<f32>(pos, 1.0);
    o.color = color;
    return o;
}

@fragment
fn solid_fs(i: SolidOut) -> @location(0) vec4<f32> {
    return i.color;
}

// ---------------------------------------------------------------- lines (ribbons)

// One ribbon corner: both ends of the segment, which end this vertex sits at
// (`end` 0 or 1), which side (`side` -1 or 1), the width in px.
@vertex
fn line_vs(
    @location(0) a: vec3<f32>,
    @location(1) b: vec3<f32>,
    @location(2) end_side_width: vec3<f32>,
    @location(3) color: vec4<f32>,
) -> SolidOut {
    let ca = u.view_proj * vec4<f32>(a, 1.0);
    let cb = u.view_proj * vec4<f32>(b, 1.0);
    let wa = max(ca.w, 1e-5);
    let wb = max(cb.w, 1e-5);
    let half_vp = u.viewport.xy * 0.5;
    let sa = ca.xy / wa * half_vp;
    let sb = cb.xy / wb * half_vp;
    var dir = sb - sa;
    let len = length(dir);
    if (len < 1e-6) {
        dir = vec2<f32>(1.0, 0.0);
    } else {
        dir = dir / len;
    }
    let normal = vec2<f32>(-dir.y, dir.x);
    var here = ca;
    if (end_side_width.x > 0.5) {
        here = cb;
    }
    let off_px = normal * end_side_width.y * end_side_width.z * 0.5;
    let off_ndc = off_px / half_vp;
    var o: SolidOut;
    o.clip = vec4<f32>(here.xy + off_ndc * here.w, here.z, here.w);
    o.color = color;
    return o;
}

// ---------------------------------------------------------------- text (SDF glyphs)

struct TextOut {
    @builtin(position) clip: vec4<f32>,
    @location(0) uv: vec2<f32>,
    @location(1) color: vec4<f32>,
};

@vertex
fn text_vs(@location(0) pos: vec3<f32>, @location(1) uv: vec2<f32>, @location(2) color: vec4<f32>) -> TextOut {
    var o: TextOut;
    o.clip = u.view_proj * vec4<f32>(pos, 1.0);
    o.uv = uv;
    o.color = color;
    return o;
}

@fragment
fn text_fs(i: TextOut) -> @location(0) vec4<f32> {
    let d = textureSample(atlas, atlas_smp, i.uv).r;
    // one screen pixel of the distance field, so the edge is ~1 px wide at any zoom
    let w = max(fwidth(d), 1e-4);
    let a = clamp((d - 0.5) / w + 0.5, 0.0, 1.0) * i.color.a;
    if (a < 0.01) {
        discard;
    }
    return vec4<f32>(i.color.rgb, a);
}