GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
src/draw/scene3d_image.wgsl (2.4K)
1 // A textured quad in the 3D scene pass: `SceneImage`. The uniform block is
2 // scene3d.wgsl's own, slot for slot — image draws take their uniforms from
3 // the same per-frame buffer the mesh draws do — and the texture is a user
4 // image's descriptor set, the one the 2D pass draws it with.
5 struct Uniforms {
6 mvp: mat4x4<f32>,
7 window_size: vec2<f32>,
8 window_radius: f32,
9 corner_shape: f32,
10 wire_tint: vec4<f32>,
11 opacity: f32,
12 is_wire: f32,
13 prelit: f32,
14 }
15
16 @group(0) @binding(0) var<uniform> uniforms: Uniforms;
17 @group(1) @binding(0) var t_image: texture_2d<f32>;
18 @group(1) @binding(1) var s_image: sampler;
19
20 // scene3d.wgsl's window_corner_distance, kept in lockstep with it.
21 fn window_corner_distance(pos: vec2<f32>) -> f32 {
22 let w = uniforms.window_size.x;
23 let h = uniforms.window_size.y;
24 let r = uniforms.window_radius;
25
26 if (pos.x < 0.0 || pos.x > w || pos.y < 0.0 || pos.y > h) {
27 return 1e5;
28 }
29 if (r <= 0.0) {
30 return -1e5;
31 }
32 let q = abs(pos - vec2f(w * 0.5, h * 0.5)) - vec2f(w * 0.5 - r, h * 0.5 - r);
33 if (q.x > 0.0 && q.y > 0.0) {
34 let shape = uniforms.corner_shape;
35 if (shape > 2.001) {
36 let lp = max(pow(pow(q.x, shape) + pow(q.y, shape), 1.0 / shape), 1e-4);
37 let g = vec2f(pow(q.x / lp, shape - 1.0), pow(q.y / lp, shape - 1.0));
38 return (lp - r) / max(length(g), 1e-4);
39 }
40 return length(q) - r;
41 }
42 return -1e5;
43 }
44
45 struct VertexOutput {
46 @builtin(position) position: vec4f,
47 @location(0) uv: vec2f,
48 };
49
50 @vertex
51 fn vs_main(
52 @location(0) position: vec3f,
53 @location(1) uv: vec2f,
54 ) -> VertexOutput {
55 var out: VertexOutput;
56 out.position = uniforms.mvp * vec4f(position, 1.0);
57 out.uv = uv;
58 return out;
59 }
60
61 @fragment
62 fn fs_main(in: VertexOutput) -> @location(0) vec4f {
63 // Sampled ahead of any discard: implicit derivatives are undefined after
64 // non-uniform control flow.
65 let texel = textureSample(t_image, s_image, in.uv);
66 let cov = 1.0 - smoothstep(-0.5, 0.5, window_corner_distance(in.position.xy));
67 let alpha = texel.a * cov * uniforms.opacity;
68 // The pipeline writes depth, and a texel that shows nothing must not
69 // hide what is drawn behind it afterwards.
70 if (alpha <= 0.002) {
71 discard;
72 }
73 // Unlit: a picture carries its own light.
74 return vec4f(texel.rgb, alpha);
75 }