Path: blob/main/examples/shader/shader_material_wesl.rs
6595 views
//! A shader that uses the WESL shading language.12use bevy::{3mesh::MeshVertexBufferLayoutRef,4pbr::{MaterialPipeline, MaterialPipelineKey},5prelude::*,6reflect::TypePath,7render::render_resource::{8AsBindGroup, RenderPipelineDescriptor, SpecializedMeshPipelineError,9},10shader::{ShaderDefVal, ShaderRef},11};1213/// This example uses shader source files from the assets subdirectory14const FRAGMENT_SHADER_ASSET_PATH: &str = "shaders/custom_material.wesl";1516fn main() {17App::new()18.add_plugins((19DefaultPlugins,20MaterialPlugin::<CustomMaterial>::default(),21CustomMaterialPlugin,22))23.add_systems(Startup, setup)24.add_systems(Update, update)25.run();26}2728/// A plugin that loads the custom material shader29pub struct CustomMaterialPlugin;3031/// An example utility shader that is used by the custom material32#[expect(33dead_code,34reason = "used to kept a strong handle, shader is referenced by the material"35)]36#[derive(Resource)]37struct UtilityShader(Handle<Shader>);3839impl Plugin for CustomMaterialPlugin {40fn build(&self, app: &mut App) {41let handle = app42.world_mut()43.resource_mut::<AssetServer>()44.load::<Shader>("shaders/util.wesl");45app.insert_resource(UtilityShader(handle));46}47}4849/// set up a simple 3D scene50fn setup(51mut commands: Commands,52mut meshes: ResMut<Assets<Mesh>>,53mut materials: ResMut<Assets<CustomMaterial>>,54) {55// cube56commands.spawn((57Mesh3d(meshes.add(Cuboid::default())),58MeshMaterial3d(materials.add(CustomMaterial {59time: Vec4::ZERO,60party_mode: false,61})),62Transform::from_xyz(0.0, 0.5, 0.0),63));6465// camera66commands.spawn((67Camera3d::default(),68Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),69));70}7172fn update(73time: Res<Time>,74mut query: Query<(&MeshMaterial3d<CustomMaterial>, &mut Transform)>,75mut materials: ResMut<Assets<CustomMaterial>>,76keys: Res<ButtonInput<KeyCode>>,77) {78for (material, mut transform) in query.iter_mut() {79let material = materials.get_mut(material).unwrap();80material.time.x = time.elapsed_secs();81if keys.just_pressed(KeyCode::Space) {82material.party_mode = !material.party_mode;83}8485if material.party_mode {86transform.rotate(Quat::from_rotation_y(0.005));87}88}89}9091// This is the struct that will be passed to your shader92#[derive(Asset, TypePath, AsBindGroup, Clone)]93#[bind_group_data(CustomMaterialKey)]94struct CustomMaterial {95// Needed for 16 bit alignment in WebGL296#[uniform(0)]97time: Vec4,98party_mode: bool,99}100101#[repr(C)]102#[derive(Eq, PartialEq, Hash, Copy, Clone)]103struct CustomMaterialKey {104party_mode: bool,105}106107impl From<&CustomMaterial> for CustomMaterialKey {108fn from(material: &CustomMaterial) -> Self {109Self {110party_mode: material.party_mode,111}112}113}114115impl Material for CustomMaterial {116fn fragment_shader() -> ShaderRef {117FRAGMENT_SHADER_ASSET_PATH.into()118}119120fn specialize(121_pipeline: &MaterialPipeline,122descriptor: &mut RenderPipelineDescriptor,123_layout: &MeshVertexBufferLayoutRef,124key: MaterialPipelineKey<Self>,125) -> Result<(), SpecializedMeshPipelineError> {126let fragment = descriptor.fragment.as_mut().unwrap();127fragment.shader_defs.push(ShaderDefVal::Bool(128"PARTY_MODE".to_string(),129key.bind_group_data.party_mode,130));131Ok(())132}133}134135136