shader_material_bindless/
shader_material_bindless.rs

1//! A material that uses bindless textures.
2
3use bevy::prelude::*;
4use bevy::render::render_resource::{AsBindGroup, ShaderType};
5use bevy::shader::ShaderRef;
6
7const SHADER_ASSET_PATH: &str = "shaders/bindless_material.wgsl";
8
9// `#[bindless(limit(4))]` indicates that we want Bevy to group materials into
10// bind groups of at most 4 materials each.
11// Note that we use the structure-level `#[uniform]` attribute to supply
12// ordinary data to the shader.
13#[derive(Asset, TypePath, AsBindGroup, Debug, Clone)]
14#[uniform(0, BindlessMaterialUniform, binding_array(10))]
15#[bindless(limit(4))]
16struct BindlessMaterial {
17    color: LinearRgba,
18    // This will be exposed to the shader as a binding array of 4 textures and a
19    // binding array of 4 samplers.
20    #[texture(1)]
21    #[sampler(2)]
22    color_texture: Option<Handle<Image>>,
23}
24
25// This buffer will be presented to the shader as `@binding(10)`.
26#[derive(ShaderType)]
27struct BindlessMaterialUniform {
28    color: LinearRgba,
29}
30
31impl<'a> From<&'a BindlessMaterial> for BindlessMaterialUniform {
32    fn from(material: &'a BindlessMaterial) -> Self {
33        BindlessMaterialUniform {
34            color: material.color,
35        }
36    }
37}
38
39// The entry point.
40fn main() {
41    App::new()
42        .add_plugins((
43            DefaultPlugins,
44            MaterialPlugin::<BindlessMaterial>::default(),
45        ))
46        .add_systems(Startup, setup)
47        .run();
48}
49
50// Creates a simple scene.
51fn setup(
52    mut commands: Commands,
53    mut meshes: ResMut<Assets<Mesh>>,
54    mut materials: ResMut<Assets<BindlessMaterial>>,
55    asset_server: Res<AssetServer>,
56) {
57    // Add a cube with a blue tinted texture.
58    commands.spawn((
59        Mesh3d(meshes.add(Cuboid::default())),
60        MeshMaterial3d(materials.add(BindlessMaterial {
61            color: LinearRgba::BLUE,
62            color_texture: Some(asset_server.load("branding/bevy_logo_dark.png")),
63        })),
64        Transform::from_xyz(-2.0, 0.5, 0.0),
65    ));
66
67    // Add a cylinder with a red tinted texture.
68    commands.spawn((
69        Mesh3d(meshes.add(Cylinder::default())),
70        MeshMaterial3d(materials.add(BindlessMaterial {
71            color: LinearRgba::RED,
72            color_texture: Some(asset_server.load("branding/bevy_logo_light.png")),
73        })),
74        Transform::from_xyz(2.0, 0.5, 0.0),
75    ));
76
77    // Add a camera.
78    commands.spawn((
79        Camera3d::default(),
80        Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
81    ));
82}
83
84impl Material for BindlessMaterial {
85    fn fragment_shader() -> ShaderRef {
86        SHADER_ASSET_PATH.into()
87    }
88}