Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/examples/shader/shader_material_wesl.rs
6595 views
1
//! A shader that uses the WESL shading language.
2
3
use bevy::{
4
mesh::MeshVertexBufferLayoutRef,
5
pbr::{MaterialPipeline, MaterialPipelineKey},
6
prelude::*,
7
reflect::TypePath,
8
render::render_resource::{
9
AsBindGroup, RenderPipelineDescriptor, SpecializedMeshPipelineError,
10
},
11
shader::{ShaderDefVal, ShaderRef},
12
};
13
14
/// This example uses shader source files from the assets subdirectory
15
const FRAGMENT_SHADER_ASSET_PATH: &str = "shaders/custom_material.wesl";
16
17
fn main() {
18
App::new()
19
.add_plugins((
20
DefaultPlugins,
21
MaterialPlugin::<CustomMaterial>::default(),
22
CustomMaterialPlugin,
23
))
24
.add_systems(Startup, setup)
25
.add_systems(Update, update)
26
.run();
27
}
28
29
/// A plugin that loads the custom material shader
30
pub struct CustomMaterialPlugin;
31
32
/// An example utility shader that is used by the custom material
33
#[expect(
34
dead_code,
35
reason = "used to kept a strong handle, shader is referenced by the material"
36
)]
37
#[derive(Resource)]
38
struct UtilityShader(Handle<Shader>);
39
40
impl Plugin for CustomMaterialPlugin {
41
fn build(&self, app: &mut App) {
42
let handle = app
43
.world_mut()
44
.resource_mut::<AssetServer>()
45
.load::<Shader>("shaders/util.wesl");
46
app.insert_resource(UtilityShader(handle));
47
}
48
}
49
50
/// set up a simple 3D scene
51
fn setup(
52
mut commands: Commands,
53
mut meshes: ResMut<Assets<Mesh>>,
54
mut materials: ResMut<Assets<CustomMaterial>>,
55
) {
56
// cube
57
commands.spawn((
58
Mesh3d(meshes.add(Cuboid::default())),
59
MeshMaterial3d(materials.add(CustomMaterial {
60
time: Vec4::ZERO,
61
party_mode: false,
62
})),
63
Transform::from_xyz(0.0, 0.5, 0.0),
64
));
65
66
// camera
67
commands.spawn((
68
Camera3d::default(),
69
Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
70
));
71
}
72
73
fn update(
74
time: Res<Time>,
75
mut query: Query<(&MeshMaterial3d<CustomMaterial>, &mut Transform)>,
76
mut materials: ResMut<Assets<CustomMaterial>>,
77
keys: Res<ButtonInput<KeyCode>>,
78
) {
79
for (material, mut transform) in query.iter_mut() {
80
let material = materials.get_mut(material).unwrap();
81
material.time.x = time.elapsed_secs();
82
if keys.just_pressed(KeyCode::Space) {
83
material.party_mode = !material.party_mode;
84
}
85
86
if material.party_mode {
87
transform.rotate(Quat::from_rotation_y(0.005));
88
}
89
}
90
}
91
92
// This is the struct that will be passed to your shader
93
#[derive(Asset, TypePath, AsBindGroup, Clone)]
94
#[bind_group_data(CustomMaterialKey)]
95
struct CustomMaterial {
96
// Needed for 16 bit alignment in WebGL2
97
#[uniform(0)]
98
time: Vec4,
99
party_mode: bool,
100
}
101
102
#[repr(C)]
103
#[derive(Eq, PartialEq, Hash, Copy, Clone)]
104
struct CustomMaterialKey {
105
party_mode: bool,
106
}
107
108
impl From<&CustomMaterial> for CustomMaterialKey {
109
fn from(material: &CustomMaterial) -> Self {
110
Self {
111
party_mode: material.party_mode,
112
}
113
}
114
}
115
116
impl Material for CustomMaterial {
117
fn fragment_shader() -> ShaderRef {
118
FRAGMENT_SHADER_ASSET_PATH.into()
119
}
120
121
fn specialize(
122
_pipeline: &MaterialPipeline,
123
descriptor: &mut RenderPipelineDescriptor,
124
_layout: &MeshVertexBufferLayoutRef,
125
key: MaterialPipelineKey<Self>,
126
) -> Result<(), SpecializedMeshPipelineError> {
127
let fragment = descriptor.fragment.as_mut().unwrap();
128
fragment.shader_defs.push(ShaderDefVal::Bool(
129
"PARTY_MODE".to_string(),
130
key.bind_group_data.party_mode,
131
));
132
Ok(())
133
}
134
}
135
136