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}