
# Objective I wrote a box shadow UI material naively thinking I could use the border widths attribute to hold the border radius but it doesn't work as the border widths are automatically set in the extraction function. Need to send border radius to the shader seperately for it to be viable. ## Solution Add a `border_radius` vertex attribute to the ui material. This PR also removes the normalization of border widths for custom UI materials. The regular UI shader doesn't do this so it's a bit confusing and means you can't use the logic from `ui.wgsl` in your custom UI materials. ## Testing / Showcase Made a change to the `ui_material` example to display border radius: ```cargo run --example ui_material``` <img width="569" alt="corners" src="https://github.com/user-attachments/assets/36412736-a9ee-4042-aadd-68b9cafb17cb" />
60 lines
2.2 KiB
WebGPU Shading Language
60 lines
2.2 KiB
WebGPU Shading Language
// Draws a progress bar with properties defined in CustomUiMaterial
|
|
#import bevy_ui::ui_vertex_output::UiVertexOutput
|
|
|
|
@group(1) @binding(0) var<uniform> color: vec4<f32>;
|
|
@group(1) @binding(1) var<uniform> slider: f32;
|
|
@group(1) @binding(2) var material_color_texture: texture_2d<f32>;
|
|
@group(1) @binding(3) var material_color_sampler: sampler;
|
|
@group(1) @binding(4) var<uniform> border_color: vec4<f32>;
|
|
|
|
|
|
@fragment
|
|
fn fragment(in: UiVertexOutput) -> @location(0) vec4<f32> {
|
|
let output_color = textureSample(material_color_texture, material_color_sampler, in.uv) * color;
|
|
|
|
// half size of the UI node
|
|
let half_size = 0.5 * in.size;
|
|
|
|
// position relative to the center of the UI node
|
|
let p = in.uv * in.size - half_size;
|
|
|
|
// thickness of the border closest to the current position
|
|
let b = vec2(
|
|
select(in.border_widths.x, in.border_widths.z, 0. < p.x),
|
|
select(in.border_widths.y, in.border_widths.w, 0. < p.y)
|
|
);
|
|
|
|
// select radius for the nearest corner
|
|
let rs = select(in.border_radius.xy, in.border_radius.wz, 0.0 < p.y);
|
|
let radius = select(rs.x, rs.y, 0.0 < p.x);
|
|
|
|
// distance along each axis from the corner
|
|
let d = half_size - abs(p);
|
|
|
|
// if the distance to the edge from the current position on any axis
|
|
// is less than the border width on that axis then the position is within
|
|
// the border and we return the border color
|
|
if d.x < b.x || d.y < b.y {
|
|
// select radius for the nearest corner
|
|
let rs = select(in.border_radius.xy, in.border_radius.wz, 0.0 < p.y);
|
|
let radius = select(rs.x, rs.y, 0.0 < p.x);
|
|
|
|
// determine if the point is inside the curved corner and return the corresponding color
|
|
let q = radius - d;
|
|
if radius < min(max(q.x, q.y), 0.0) + length(vec2(max(q.x, 0.0), max(q.y, 0.0))) {
|
|
return vec4(0.0);
|
|
} else {
|
|
return border_color;
|
|
}
|
|
}
|
|
|
|
// sample the texture at this position if it's to the left of the slider value
|
|
// otherwise return a fully transparent color
|
|
if in.uv.x < slider {
|
|
let output_color = textureSample(material_color_texture, material_color_sampler, in.uv) * color;
|
|
return output_color;
|
|
} else {
|
|
return vec4(0.0);
|
|
}
|
|
}
|