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.
1// This shader draws a hue ring and an inner whiteness/blackness triangle.
2import bevy_ui_render::ui_vertex_output::UiVertexOutput;
3import bevy_render::color_operations::hwb_to_linear_rgb;
4import bevy_render::maths::PI_2;
6// Constants must be the same as in `color_wheel.rs`
7const RING_WIDTH: f32 = 12.0;
8const SPACING: f32 = 4.0;
9const MIN_HEIGHT: f32 = 100.0;
10const PADDING: f32 = 4.0;
11const MIN_DIAMETER: f32 = MIN_HEIGHT - 2.0 * PADDING;
13struct ColorPlaneUniform {
14 // Hue in degrees, in the range [0, 360).
15 hue : f32,
16 // Scale (physical pixels / logical pixels)
17 scale: f32,
18@if(SIXTEEN_BYTE_ALIGNMENT)
19 _webgl2_padding_8b : vec2<f32>,
22@group(1) @binding(0) var<uniform> uniform_data : ColorPlaneUniform;
24// 2d cross product
25fn cross_2d(a: vec2<f32>, b: vec2<f32>) -> f32 {
26 return a.x * b.y - a.y * b.x;
29// Line distance for triangle SDF, positive on left
30fn line_distance(p: vec2<f32>, a: vec2<f32>, b: vec2<f32>) -> f32 {
31 return cross_2d(b - a, p - a) / distance(a, b);
34@fragment
35fn fragment(in: UiVertexOutput) -> @location(0) vec4<f32> {
36 let scale = uniform_data.scale;
37 let min_side = max(min(in.size.x, in.size.y), MIN_DIAMETER * scale);
38 let diameters = min_side / in.size;
39 // UV space is from -0.5 to 0.5
40 let centered = (in.uv - vec2(0.5)) / diameters;
41 let radial = length(centered);
42 let aa = fwidth(radial);
44 let inner_radius = 0.5 - RING_WIDTH * scale / min_side;
45 let ring_hue = fract(atan2(centered.y, centered.x) / PI_2);
46 let ring_alpha = smoothstep(inner_radius - aa, inner_radius, radial)
47 - smoothstep(0.5 - aa, 0.5, radial);
49 let triangle_radius = 0.5 - (RING_WIDTH + 2.0 * SPACING) * scale / min_side;
50 let triangle_hue = fract(uniform_data.hue / 360.0);
51 let hue_angle = radians(uniform_data.hue);
52 let white_angle = hue_angle + PI_2 / 3.0;
53 let black_angle = hue_angle - PI_2 / 3.0;
54 let hue_point = vec2(cos(hue_angle), sin(hue_angle)) * triangle_radius;
55 let white_point = vec2(cos(white_angle), sin(white_angle)) * triangle_radius;
56 let black_point = vec2(cos(black_angle), sin(black_angle)) * triangle_radius;
58 // Calculate WB values
59 let area = cross_2d(white_point - hue_point, black_point - hue_point);
60 var whiteness = cross_2d(centered - hue_point, black_point - hue_point) / area;
61 var blackness = cross_2d(white_point - hue_point, centered - hue_point) / area;
63 // Clamp pixels outside triangle, for antialiasing
64 whiteness = clamp(whiteness, 0.0, 1.0);
65 blackness = clamp(blackness, 0.0, 1.0);
66 let wb = whiteness + blackness;
67 if wb > 1.0 {
68 whiteness /= wb;
69 blackness /= wb;
70 }
72 // Triangle SDF, winding counterclockwise, positive inside
73 let triangle_sd = min(
74 line_distance(centered, hue_point, white_point),
75 min(
76 line_distance(centered, white_point, black_point),
77 line_distance(centered, black_point, hue_point),
78 ),
79 );
80 let triangle_aa = fwidth(triangle_sd);
81 let triangle_alpha = smoothstep(-triangle_aa, 0.0, triangle_sd);
83 let alpha = min(ring_alpha + triangle_alpha, 1.0);
85 let ring_color = hwb_to_linear_rgb(vec3(ring_hue, 0.0, 0.0));
86 let triangle_color = hwb_to_linear_rgb(vec3(triangle_hue, whiteness, blackness));
87 let color = (ring_color * ring_alpha + triangle_color * triangle_alpha) / max(alpha, 0.001);
88 return vec4(color, alpha);
Contents