wde_renderer/assets/
mod.rs

1//! Renderer assets module.
2//!
3//! This module contains:
4//! - Definitions and loading logic for all assets used by the renderer, that is [`Mesh`](crate::assets::Mesh), [`Texture`](crate::assets::Texture), [`Buffer`](crate::assets::Buffer), [`Shader`](crate::assets::Shader) assets. Each asset type has its own loading logic and GPU preparation steps, defined in their respective submodules.
5//! - The [`bindings`](crate::assets::bindings) submodule, which provides utilities for defining custom render resources and bindings.
6//! - A set of default utility meshes, defined in the [`meshes`](crate::assets::meshes) submodule.
7//!
8//! # Asset loading
9//! ## Default asset loading
10//! Assets can be loaded with the default options using the `AssetServer` as usual:
11//! ```
12//! let texture_handle: Handle<Texture> = asset_server.load("res/my_texture.png");
13//! ```
14//!
15//! ## Load with options
16//! Some assets can be loaded with options, for example a texture can be loaded with specific sampler settings:
17//! ```
18//! let texture_handle: Handle<Texture> = assets_server.load_with_settings("res/my_texture.png",
19//!     |settings: &mut TextureLoaderSettings| {
20//!         settings.label = "my_texture".to_string();
21//!         settings.format = TextureFormat::R8Unorm;
22//!         settings.usages = TextureUsages::TEXTURE_BINDING;
23//!     });
24//! ```
25//!
26//! ## Custom asset creation
27//! Assets can also be created from raw data, for example a texture can be created from raw pixel data:
28//! ```
29//! let texture_handle: Handle<Texture> = asset_server.add(Texture {
30//!     label: "My Texture".to_string(),
31//!     size: (256, 256),
32//!     format: TextureFormat::Rgba8Unorm,
33//!     usages: TextureUsages::COPY_DST | TextureUsages::TEXTURE_BINDING,
34//!     data: vec![0u8; 256 * 256 * 4], // RGBA8 texture with all pixels set to transparent black
35//!     ..Default::default()
36//! });
37//! ```
38//!
39//! # Render assets and render bindings
40//! Assets defined in this module can be used as GPU resources in render bindings/pipelines by referencing them in the corresponding preparation systems.
41//! The main types to be aware of are:
42//! - [`RenderData`](crate::assets::bindings::RenderData): declares GPU resources (buffers/textures) and how they are recreated.
43//! - [`RenderBinding`](crate::assets::bindings::RenderBinding): builds a bind group by referencing resources exposed by one or more [`RenderData`](crate::assets::bindings::RenderData) instances.
44//!
45//! ## RenderData
46//! A [`RenderData`](crate::assets::bindings::RenderData) is used to allocate reusable GPU resources.
47//! It is registered with [`RenderDataRegisterPlugin`](crate::assets::bindings::RenderDataRegisterPlugin), which:
48//! - creates and prepares the corresponding [`GpuRenderData`](crate::assets::bindings::GpuRenderData),
49//! - optionally recreates it when [`RenderData::recreate`](crate::assets::bindings::RenderData::recreate) returns `Some(true)`.
50//!
51//! Typical example (deferred textures):
52//! ```
53//! #[derive(Asset, Clone, TypePath, Default)]
54//! pub struct DeferredTextures;
55//! impl DeferredTextures {
56//!     pub const ALBEDO_RESOLVED_IDX: u32 = 1;
57//!     pub const DEMO_BUFFER: u32 = 2;
58//! }
59//!
60//! impl RenderData for DeferredTextures {
61//!     type Params = (SQuery<&'static Window>, SRes<Messages<SurfaceResized>>);
62//!
63//!     fn describe((window, _): &mut SystemParamItem<Self::Params>, builder: &mut RenderDataBuilder) {
64//!         let size = {
65//!             let window = window.single().unwrap();
66//!             (window.resolution.physical_width(), window.resolution.physical_height())
67//!         };
68//!         let usages = TextureUsages::RENDER_ATTACHMENT | TextureUsages::TEXTURE_BINDING;
69//!         builder
70//!             .add_texture(Self::ALBEDO_RESOLVED_IDX,
71//!                 Texture {
72//!                     label: "pbr-albedo-resolved".to_string(),
73//!                     size,
74//!                     format: TextureFormat::Rgba8UnormSrgb,
75//!                     usages,
76//!                     ..Default::default()
77//!                 },
78//!             )
79//!             .add_buffer(Self::DEMO_BUFFER,
80//!                 Buffer {
81//!                     label: "demo-buffer".to_string(),
82//!                     size: 1024,
83//!                     usage: BufferUsage::STORAGE | BufferUsage::COPY_DST,
84//!                     content: None,
85//!                 },
86//!             );
87//!     }
88//!
89//!     fn recreate((_, surface_resized): &SystemParamItem<Self::Params>) -> Option<bool> {
90//!         Some(surface_resized.get_cursor().read(surface_resized).next().is_some())
91//!     }
92//! }
93//!
94//! pub struct DeferredTexturesPlugin;
95//! impl Plugin for DeferredTexturesPlugin {
96//!     fn build(&self, app: &mut App) {
97//!         app.add_plugins(RenderDataRegisterPlugin::<DeferredTextures>::default());
98//!     }
99//! }
100//! ```
101//!
102//! To later update the content of a render data buffer/texture, request [`ResRenderData`](crate::assets::bindings::ResRenderData) in a system and use the corresponding getters to access the GPU resource:
103//! ```rust
104//! fn update_buffer(mut deferred_textures: ResRenderData<DeferredTextures>, mut buffers: ResMut<GpuBuffers>) {
105//!     let buffer = match buffer.iter().next() {
106//!         Some((_, buffer)) => match buffer.get_buffer(DeferredTextures::DEMO_BUFFER) {
107//!             Some(buffer) => buffer,
108//!             None => return
109//!         },
110//!         _ => return
111//!     };
112//!
113//!     // Update the buffer content with new data
114//!     // (...)
115//! }
116//! ```
117//!
118//! ## RenderBinding
119//! A [`RenderBinding`](crate::assets::bindings::RenderBinding) maps resources from [`GpuRenderData`](crate::assets::bindings::GpuRenderData) into a bind group layout + bind group pair ([`GpuRenderBinding`](crate::assets::bindings::GpuRenderBinding)).
120//! It is registered with [`RenderBindingRegisterPlugin`](crate::assets::bindings::RenderBindingRegisterPlugin).
121//!
122//! Example: build a bind group from the resolved deferred textures.
123//! ```
124//!
125//! #[derive(TypePath, Default, Clone, Asset)]
126//! struct RenderBindingResolved;
127//! impl RenderBinding for RenderBindingResolved {
128//!     type Params = SRenderData<DeferredTextures>;
129//!
130//!     fn describe(
131//!         deferred_textures: &SystemParamItem<Self::Params>,
132//!         builder: &mut RenderBindingBuilder,
133//!     ) {
134//!         builder
135//!             .add_texture_view(deferred_textures, DeferredTextures::ALBEDO_RESOLVED_IDX)
136//!             .add_texture_sampler(deferred_textures, DeferredTextures::ALBEDO_RESOLVED_IDX);
137//!     }
138//!
139//!     fn label(&self) -> &'static str { "deferred-textures-resolved-binding" }
140//! }
141//!
142//! pub struct DeferredBindingPlugin;
143//! impl Plugin for DeferredBindingPlugin {
144//!     fn build(&self, app: &mut App) {
145//!         app.add_plugins(RenderBindingRegisterPlugin::<RenderBindingResolved>::default());
146//!     }
147//! }
148//! ```
149//!
150//! ## Referencing In Pipelines
151//! To use a registered render binding in a pipeline preparation system, request [`SRenderBinding`](crate::assets::bindings::SRenderBinding) in the render asset params and use its `layout`/`bind_group`.
152//! ```
153//! type Params = (
154//!     SRenderBinding<RenderBindingResolved>
155//! );
156//!
157//! // In RenderPipelineDescriptor
158//! bind_group_layouts: vec![
159//!     // (...)
160//!     render_binding.iter().next().map(|(_, d)| d.layout.clone()),
161//! ],
162//! ```
163//!
164//! In the sub-pass, bind groups must match that same ordering:
165//! ```
166//! // (...)
167//! SubPassCommand::BindGroup(1, rbinding.iter().next().map(|(_, d)| d.bind_group.clone())),
168//! ```
169//!
170//! ## Plugin Order
171//! Register the underlying [`RenderData`](crate::assets::bindings::RenderData) plugin before the [`RenderBinding`](crate::assets::bindings::RenderBinding) plugin that depends on it.
172//! This allows the binding preparation to retry until all dependent GPU resources are ready, and to react correctly when data are recreated.
173
174mod asset;
175mod bindings;
176mod buffer;
177mod mesh;
178pub mod meshes;
179mod shader;
180mod texture;
181
182use bevy::prelude::*;
183
184pub use asset::*;
185pub use bindings::*;
186pub use buffer::*;
187pub use mesh::*;
188pub use meshes::*;
189pub use shader::*;
190pub use texture::*;
191
192pub(crate) struct AssetsPlugin;
193impl Plugin for AssetsPlugin {
194    fn build(&self, app: &mut App) {
195        // Setup the assets
196        app.add_plugins(MaterialsPlugin)
197            .init_asset_loader::<TextureLoader>()
198            .init_asset::<Texture>()
199            .init_asset_loader::<MeshLoader>()
200            .init_asset::<Mesh>()
201            .init_asset_loader::<ShaderLoader>()
202            .init_asset::<Shader>()
203            .init_asset::<Buffer>();
204
205        // Add resource loaders to transfer the assets to the GPU
206        app.add_plugins(RenderAssetsPlugin::<GpuMesh>::default())
207            .add_plugins(RenderAssetsPlugin::<GpuTexture>::default())
208            .add_plugins(RenderAssetsPlugin::<GpuBuffer>::default());
209
210        // Register the components to the reflect system
211        app.register_type::<Mesh3d>();
212    }
213}