Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/examples/shader/shader_defs.rs
6595 views
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.wgsl";
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
}
102
103