docs/bevy/examples/shader/shader_defs.rs 2.9 K · 101 lines · raw · history

1 //! A shader that uses "shaders defs", which selectively toggle parts of a shader.
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::ShaderRef,
12 };
13
14 /// This example uses a shader source file from the assets subdirectory
15 const SHADER_ASSET_PATH: &str = "shaders/shader_defs.wesl";
16
17 fn main() {
18 App::new()
19 .add_plugins((DefaultPlugins, MaterialPlugin::<CustomMaterial>::default()))
20 .add_systems(Startup, setup)
21 .run();
22 }
23
24 /// set up a simple 3D scene
25 fn setup(
26 mut commands: Commands,
27 mut meshes: ResMut<Assets<Mesh>>,
28 mut materials: ResMut<Assets<CustomMaterial>>,
29 ) {
30 // blue cube
31 commands.spawn((
32 Mesh3d(meshes.add(Cuboid::default())),
33 MeshMaterial3d(materials.add(CustomMaterial {
34 color: LinearRgba::BLUE,
35 is_red: false,
36 })),
37 Transform::from_xyz(-1.0, 0.5, 0.0),
38 ));
39
40 // red cube (with green color overridden by the IS_RED "shader def")
41 commands.spawn((
42 Mesh3d(meshes.add(Cuboid::default())),
43 MeshMaterial3d(materials.add(CustomMaterial {
44 color: LinearRgba::GREEN,
45 is_red: true,
46 })),
47 Transform::from_xyz(1.0, 0.5, 0.0),
48 ));
49
50 // camera
51 commands.spawn((
52 Camera3d::default(),
53 Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
54 ));
55 }
56
57 impl Material for CustomMaterial {
58 fn fragment_shader() -> ShaderRef {
59 SHADER_ASSET_PATH.into()
60 }
61
62 fn specialize(
63 _pipeline: &MaterialPipeline,
64 descriptor: &mut RenderPipelineDescriptor,
65 _layout: &MeshVertexBufferLayoutRef,
66 key: MaterialPipelineKey<Self>,
67 ) -> Result<(), SpecializedMeshPipelineError> {
68 if key.bind_group_data.is_red {
69 let fragment = descriptor.fragment.as_mut().unwrap();
70 fragment.shader_defs.push("IS_RED".into());
71 }
72 Ok(())
73 }
74 }
75
76 // This is the struct that will be passed to your shader
77 #[derive(Asset, TypePath, AsBindGroup, Debug, Clone)]
78 #[bind_group_data(CustomMaterialKey)]
79 struct CustomMaterial {
80 #[uniform(0)]
81 color: LinearRgba,
82 is_red: bool,
83 }
84
85 // This key is used to identify a specific permutation of this material pipeline.
86 // In this case, we specialize on whether or not to configure the "IS_RED" shader def.
87 // Specialization keys should be kept as small / cheap to hash as possible,
88 // as they will be used to look up the pipeline for each drawn entity with this material type,
89 #[repr(C)]
90 #[derive(Eq, PartialEq, Hash, Copy, Clone)]
91 struct CustomMaterialKey {
92 is_red: bool,
93 }
94
95 impl From<&CustomMaterial> for CustomMaterialKey {
96 fn from(material: &CustomMaterial) -> Self {
97 Self {
98 is_red: material.is_red,
99 }
100 }
101 }