Search across packages, versions, files, declarations, and comments. Use multiple terms to narrow results (AND), and add @vertex, @fragment, or @compute to filter by shader stage.
1import bevy_render::view::View;
2import bevy_render::globals::Globals;
3import package::ui::{
4 select_corner_radius
5};
7const PI: f32 = 3.14159265358979323846;
8const SAMPLES: u32 = constants::SHADOW_SAMPLES;
10@group(0) @binding(0) var<uniform> view: View;
12struct BoxShadowVertexOutput {
13 @builtin(position) position: vec4<f32>,
14 @location(0) point: vec2<f32>,
15 @location(1) color: vec4<f32>,
16 @location(2) @interpolate(flat) size: vec2<f32>,
17 @location(3) @interpolate(flat) radius_x: vec4<f32>,
18 @location(4) @interpolate(flat) radius_y: vec4<f32>,
19 @location(5) @interpolate(flat) blur: f32,
22fn gaussian(x: f32, sigma: f32) -> f32 {
23 return exp(-(x * x) / (2. * sigma * sigma)) / (sqrt(2. * PI) * sigma);
26/// Approximates the Gauss error function: https://en.wikipedia.org/wiki/Error_function
27fn erf(p: vec2<f32>) -> vec2<f32> {
28 let s = sign(p);
29 let a = abs(p);
30 // fourth degree polynomial approximation for erf
31 var result = 1.0 + (0.278393 + (0.230389 + 0.078108 * (a * a)) * a) * a;
32 result = result * result;
33 return s - s / (result * result);
36fn horizontalRoundedBoxShadow(x: f32, y: f32, blur: f32, radius: vec2<f32>, half_size: vec2<f32>) -> f32 {
37 var c = half_size.x;
38 if 0.0 < min(radius.x, radius.y) {
39 let d = min(half_size.y - radius.y - abs(y), 0.);
40 c = half_size.x - radius.x + radius.x * sqrt(max(0., 1. - d * d / (radius.y * radius.y)));
41 }
42 let integral = 0.5 + 0.5 * erf((x + vec2(-c, c)) * (sqrt(0.5) / blur));
43 return integral.y - integral.x;
46fn roundedBoxShadow(
47 lower: vec2<f32>,
48 upper: vec2<f32>,
49 point: vec2<f32>,
50 blur: f32,
51 corners_x: vec4<f32>,
52 corners_y: vec4<f32>,
53) -> f32 {
54 let center = (lower + upper) * 0.5;
55 let half_size = (upper - lower) * 0.5;
56 let p = point - center;
57 let low = p.y - half_size.y;
58 let high = p.y + half_size.y;
59 let start = clamp(-3. * blur, low, high);
60 let end = clamp(3. * blur, low, high);
61 let step = (end - start) / f32(SAMPLES);
62 var y = start + step * 0.5;
63 var value: f32 = 0.0;
64 for (var i: u32 = 0; i < SAMPLES; i++) {
65 let corner = select_corner_radius(p, corners_x, corners_y);
66 value += horizontalRoundedBoxShadow(p.x, p.y - y, blur, corner, half_size) * gaussian(y, blur) * step;
67 y += step;
68 }
69 return value;
72@vertex
73fn vertex(
74 @location(0) vertex_position: vec3<f32>,
75 @location(1) uv: vec2<f32>,
76 @location(2) vertex_color: vec4<f32>,
77 @location(3) size: vec2<f32>,
78 @location(4) radius_x: vec4<f32>,
79 @location(5) radius_y: vec4<f32>,
80 @location(6) blur: f32,
81 @location(7) bounds: vec2<f32>,
82) -> BoxShadowVertexOutput {
83 var out: BoxShadowVertexOutput;
84 out.position = view.clip_from_world * vec4(vertex_position, 1.0);
85 out.point = (uv.xy - 0.5) * bounds;
86 out.color = vertex_color;
87 out.size = size;
88 out.radius_x = radius_x;
89 out.radius_y = radius_y;
90 out.blur = blur;
91 return out;
94@fragment
95fn fragment(
96 in: BoxShadowVertexOutput,
97) -> @location(0) vec4<f32> {
98 let g = in.color.a * roundedBoxShadow(-0.5 * in.size, 0.5 * in.size, in.point, max(in.blur, 0.01), in.radius_x, in.radius_y);
99 return vec4(in.color.rgb, g);
Contents