Skip to content

Commit fd232ad

Browse files
MarkusTheOrtickshonpemockersf
authored
Add UI Materials (bevyengine#9506)
# Objective - Add Ui Materials so that UI can render more complex and animated widgets. - Fixes bevyengine#5607 ## Solution - Create a UiMaterial trait for specifying a Shader Asset and Bind Group Layout/Data. - Create a pipeline for rendering these Materials inside the Ui layout/tree. - Create a MaterialNodeBundle for simple spawning. ## Changelog - Created a `UiMaterial` trait for specifying a Shader asset and Bind Group. - Created a `UiMaterialPipeline` for rendering said Materials. - Added Example [`ui_material` ](https://github.com/MarkusTheOrt/bevy/blob/ui_material/examples/ui/ui_material.rs) for example usage. - Created [`UiVertexOutput`](https://github.com/MarkusTheOrt/bevy/blob/ui_material/crates/bevy_ui/src/render/ui_vertex_output.wgsl) export as VertexData for shaders. - Created [`material_ui`](https://github.com/MarkusTheOrt/bevy/blob/ui_material/crates/bevy_ui/src/render/ui_material.wgsl) shader as default for both Vertex and Fragment shaders. --------- Co-authored-by: ickshonpe <david.curthoys@googlemail.com> Co-authored-by: François <mockersf@gmail.com>
1 parent 6a7b215 commit fd232ad

File tree

11 files changed

+1090
-6
lines changed

11 files changed

+1090
-6
lines changed

Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2412,6 +2412,17 @@ description = "Demonstrates resizing and responding to resizing a window"
24122412
category = "Window"
24132413
wasm = true
24142414

2415+
[[example]]
2416+
name = "ui_material"
2417+
path = "examples/ui/ui_material.rs"
2418+
doc-scrape-examples = true
2419+
2420+
[package.metadata.example.ui_material]
2421+
name = "UI Material"
2422+
description = "Demonstrates creating and using custom Ui materials"
2423+
category = "UI (User Interface)"
2424+
wasm = true
2425+
24152426
[profile.wasm-release]
24162427
inherits = "release"
24172428
opt-level = "z"

assets/shaders/circle_shader.wgsl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// This shader draws a circle with a given input color
2+
#import bevy_ui::ui_vertex_output::UiVertexOutput
3+
4+
struct CustomUiMaterial {
5+
@location(0) color: vec4<f32>
6+
}
7+
8+
@group(1) @binding(0)
9+
var<uniform> input: CustomUiMaterial;
10+
11+
@fragment
12+
fn fragment(in: UiVertexOutput) -> @location(0) vec4<f32> {
13+
// the UVs are now adjusted around the middle of the rect.
14+
let uv = in.uv * 2.0 - 1.0;
15+
16+
// circle alpha, the higher the power the harsher the falloff.
17+
let alpha = 1.0 - pow(sqrt(dot(uv, uv)), 100.0);
18+
19+
return vec4<f32>(input.color.rgb, alpha);
20+
}
21+

crates/bevy_ui/src/lib.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
pub mod camera_config;
99
pub mod measurement;
1010
pub mod node_bundles;
11+
pub mod ui_material;
1112
pub mod update;
1213
pub mod widget;
1314

@@ -29,15 +30,16 @@ pub use geometry::*;
2930
pub use layout::*;
3031
pub use measurement::*;
3132
pub use render::*;
33+
pub use ui_material::*;
3234
pub use ui_node::*;
3335
use widget::UiImageSize;
3436

3537
#[doc(hidden)]
3638
pub mod prelude {
3739
#[doc(hidden)]
3840
pub use crate::{
39-
camera_config::*, geometry::*, node_bundles::*, ui_node::*, widget::Button, widget::Label,
40-
Interaction, UiScale,
41+
camera_config::*, geometry::*, node_bundles::*, ui_material::*, ui_node::*, widget::Button,
42+
widget::Label, Interaction, UiMaterialPlugin, UiScale,
4143
};
4244
}
4345

crates/bevy_ui/src/node_bundles.rs

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::widget::TextFlags;
55
use crate::{
66
widget::{Button, UiImageSize},
77
BackgroundColor, BorderColor, ContentSize, FocusPolicy, Interaction, Node, Style, UiImage,
8-
UiTextureAtlasImage, ZIndex,
8+
UiMaterial, UiTextureAtlasImage, ZIndex,
99
};
1010
use bevy_asset::Handle;
1111
use bevy_ecs::bundle::Bundle;
@@ -342,3 +342,52 @@ impl Default for ButtonBundle {
342342
}
343343
}
344344
}
345+
346+
/// A UI node that is rendered using a [`UiMaterial`]
347+
#[derive(Bundle, Clone, Debug)]
348+
pub struct MaterialNodeBundle<M: UiMaterial> {
349+
/// Describes the logical size of the node
350+
pub node: Node,
351+
/// Styles which control the layout (size and position) of the node and it's children
352+
/// In some cases these styles also affect how the node drawn/painted.
353+
pub style: Style,
354+
/// The [`UiMaterial`] used to render the node.
355+
pub material: Handle<M>,
356+
/// Whether this node should block interaction with lower nodes
357+
pub focus_policy: FocusPolicy,
358+
/// The transform of the node
359+
///
360+
/// This field is automatically managed by the UI layout system.
361+
/// To alter the position of the `NodeBundle`, use the properties of the [`Style`] component.
362+
pub transform: Transform,
363+
/// The global transform of the node
364+
///
365+
/// This field is automatically managed by the UI layout system.
366+
/// To alter the position of the `NodeBundle`, use the properties of the [`Style`] component.
367+
pub global_transform: GlobalTransform,
368+
/// Describes the visibility properties of the node
369+
pub visibility: Visibility,
370+
/// Inherited visibility of an entity.
371+
pub inherited_visibility: InheritedVisibility,
372+
/// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering
373+
pub view_visibility: ViewVisibility,
374+
/// Indicates the depth at which the node should appear in the UI
375+
pub z_index: ZIndex,
376+
}
377+
378+
impl<M: UiMaterial> Default for MaterialNodeBundle<M> {
379+
fn default() -> Self {
380+
Self {
381+
node: Default::default(),
382+
style: Default::default(),
383+
material: Default::default(),
384+
focus_policy: Default::default(),
385+
transform: Default::default(),
386+
global_transform: Default::default(),
387+
visibility: Default::default(),
388+
inherited_visibility: Default::default(),
389+
view_visibility: Default::default(),
390+
z_index: Default::default(),
391+
}
392+
}
393+
}

crates/bevy_ui/src/render/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
mod pipeline;
22
mod render_pass;
3+
mod ui_material_pipeline;
34

45
use bevy_core_pipeline::{core_2d::Camera2d, core_3d::Camera3d};
56
use bevy_hierarchy::Parent;
@@ -9,6 +10,7 @@ use bevy_render::{render_resource::BindGroupEntries, ExtractSchedule, Render};
910
use bevy_window::{PrimaryWindow, Window};
1011
pub use pipeline::*;
1112
pub use render_pass::*;
13+
pub use ui_material_pipeline::*;
1214

1315
use crate::Outline;
1416
use crate::{
@@ -253,7 +255,7 @@ pub fn extract_atlas_uinodes(
253255
}
254256
}
255257

256-
fn resolve_border_thickness(value: Val, parent_width: f32, viewport_size: Vec2) -> f32 {
258+
pub(crate) fn resolve_border_thickness(value: Val, parent_width: f32, viewport_size: Vec2) -> f32 {
257259
match value {
258260
Val::Auto => 0.,
259261
Val::Px(px) => px.max(0.),
@@ -695,14 +697,14 @@ impl Default for UiMeta {
695697
}
696698
}
697699

698-
const QUAD_VERTEX_POSITIONS: [Vec3; 4] = [
700+
pub(crate) const QUAD_VERTEX_POSITIONS: [Vec3; 4] = [
699701
Vec3::new(-0.5, -0.5, 0.0),
700702
Vec3::new(0.5, -0.5, 0.0),
701703
Vec3::new(0.5, 0.5, 0.0),
702704
Vec3::new(-0.5, 0.5, 0.0),
703705
];
704706

705-
const QUAD_INDICES: [usize; 6] = [0, 2, 3, 0, 1, 2];
707+
pub(crate) const QUAD_INDICES: [usize; 6] = [0, 2, 3, 0, 1, 2];
706708

707709
#[derive(Component)]
708710
pub struct UiBatch {
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#import bevy_render::view::View
2+
#import bevy_ui::ui_vertex_output::UiVertexOutput
3+
4+
@group(0) @binding(0)
5+
var<uniform> view: View;
6+
7+
@vertex
8+
fn vertex(
9+
@location(0) vertex_position: vec3<f32>,
10+
@location(1) vertex_uv: vec2<f32>,
11+
@location(2) border_widths: vec4<f32>,
12+
) -> UiVertexOutput {
13+
var out: UiVertexOutput;
14+
out.uv = vertex_uv;
15+
out.position = view.view_proj * vec4<f32>(vertex_position, 1.0);
16+
out.border_widths = border_widths;
17+
return out;
18+
}
19+
20+
@fragment
21+
fn fragment(in: UiVertexOutput) -> @location(0) vec4<f32> {
22+
return vec4<f32>(1.0);
23+
}

0 commit comments

Comments
 (0)