Skip to content

UI 材质

当 Node 的背景色、边框、圆角满足不了你的视觉需求时,UiMaterial 允许你用自定义 WGSL shader 绘制 UI 元素。

UiMaterial 基础

自定义 UI 材质分三步:

  1. 定义材质结构体,用 #[derive(AsBindGroup, Asset, TypePath)] 标注;
  2. 实现 UiMaterial trait,指定 fragment shader 路径;
  3. 注册 UiMaterialPlugin::<YourMaterial>,用 MaterialNode(handle) 组件把材质挂到 UI Node 上。
rust
use bevy::prelude::*;
use bevy::render::render_resource::*;
use bevy::shader::ShaderRef;

#[derive(AsBindGroup, Asset, TypePath, Debug, Clone)]
struct MyUiMaterial {
    #[uniform(0)]
    color: Vec4,
}

impl UiMaterial for MyUiMaterial {
    fn fragment_shader() -> ShaderRef {
        "shaders/my_ui.wgsl".into()
    }
}

fn setup(mut commands: Commands, mut materials: ResMut<Assets<MyUiMaterial>>) {
    commands.spawn((
        Node { width: px(200), height: px(100), ..default() },
        MaterialNode(materials.add(MyUiMaterial {
            color: Vec4::new(1.0, 0.5, 0.0, 1.0),
        })),
    ));
}

MaterialNode 和普通 Node 共存——你仍然可以设置 borderborder_radiusOutlineBoxShadow 等属性。材质只影响背景的绘制方式。

动态更新

材质的 uniform 字段可以在运行时修改。查询 MaterialNode<YourMaterial> 拿到 Handle,再从 Assets<YourMaterial> 资源里取出材质修改即可:

rust
fn animate(
    mut materials: ResMut<Assets<MyUiMaterial>>,
    q: Query<&MaterialNode<MyUiMaterial>>,
    time: Res<Time>,
) {
    for handle in &q {
        if let Some(mat) = materials.get_mut(handle) {
            mat.color.x = time.elapsed_secs().sin() * 0.5 + 0.5;
        }
    }
}

适用场景

UI 材质适合:

  • 渐变、条纹、波纹等程序化背景;
  • 需要 shader 特效的 UI 元素(进度条填充动画、发光边框);
  • 自定义形状的裁切(超出圆角矩形的范围)。

不适合:简单的纯色/图片背景——那些用 BackgroundColorImageNode 就够了。

本章不深入 shader 编写(那是第 36 章的领地),这里只建立"UI 材质存在"的认知。官方示例 ui/ui_material.rs 有完整可运行的参考。