Skip to content

Commit 1679b3e

Browse files
committed
Use embedded_asset to load PBR shaders
1 parent 732b2e0 commit 1679b3e

File tree

9 files changed

+177
-188
lines changed

9 files changed

+177
-188
lines changed

crates/bevy_asset/src/io/embedded/mod.rs

+79-7
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ use crate::io::{
88
memory::{Dir, MemoryAssetReader, Value},
99
AssetSource, AssetSourceBuilders,
1010
};
11+
use crate::AssetServer;
1112
use alloc::boxed::Box;
12-
use bevy_ecs::resource::Resource;
13+
use bevy_app::App;
14+
use bevy_ecs::{resource::Resource, world::World};
1315
use std::path::{Path, PathBuf};
1416

1517
#[cfg(feature = "embedded_watcher")]
@@ -132,6 +134,71 @@ impl EmbeddedAssetRegistry {
132134
}
133135
}
134136

137+
/// Trait for the [`load_embedded_asset!`] macro, to access [`AssetServer`]
138+
/// from arbitrary things.
139+
///
140+
/// [`load_embedded_asset!`]: crate::load_embedded_asset
141+
pub trait GetAssetServer {
142+
fn get_asset_server(&self) -> &AssetServer;
143+
}
144+
impl GetAssetServer for App {
145+
fn get_asset_server(&self) -> &AssetServer {
146+
self.world().get_asset_server()
147+
}
148+
}
149+
impl GetAssetServer for World {
150+
fn get_asset_server(&self) -> &AssetServer {
151+
self.resource()
152+
}
153+
}
154+
impl GetAssetServer for AssetServer {
155+
fn get_asset_server(&self) -> &AssetServer {
156+
self
157+
}
158+
}
159+
160+
/// Load an [embedded asset](crate::embedded_asset).
161+
///
162+
/// This is useful if the embedded asset in question is not publicly exposed, but
163+
/// you need to use it internally.
164+
///
165+
/// # Syntax
166+
///
167+
/// This macro takes two arguments and an optional third one:
168+
/// 1. The asset source. It may be `AssetServer`, `World` or `App`.
169+
/// 2. The path to the asset to embed, as a string literal.
170+
/// 3. Optionally, a closure of the same type as in [`AssetServer::load_with_settings`].
171+
/// Consider explicitly typing the closure argument in case of type error.
172+
///
173+
/// # Usage
174+
///
175+
/// The advantage compared to using directly [`AssetServer::load`] is:
176+
/// - This also accepts [`World`] and [`App`] arguments.
177+
/// - This uses the exact same path as `embedded_asset!`, so you can keep it
178+
/// consistent.
179+
///
180+
/// As a rule of thumb:
181+
/// - If the asset in used in the same module as it is declared using `embedded_asset!`,
182+
/// use this macro.
183+
/// - Otherwise, use `AssetServer::load`.
184+
#[macro_export]
185+
macro_rules! load_embedded_asset {
186+
(@get: $path: literal, $provider: expr) => {{
187+
let path = $crate::embedded_path!($path);
188+
let path = $crate::AssetPath::from_path_buf(path).with_source("embedded");
189+
let asset_server = $crate::io::embedded::GetAssetServer::get_asset_server($provider);
190+
(path, asset_server)
191+
}};
192+
($provider: expr, $path: literal, $settings: expr) => {{
193+
let (path, asset_server) = $crate::load_embedded_asset!(@get: $path, $provider);
194+
asset_server.load_with_settings(path, $settings)
195+
}};
196+
($provider: expr, $path: literal) => {{
197+
let (path, asset_server) = $crate::load_embedded_asset!(@get: $path, $provider);
198+
asset_server.load(path)
199+
}};
200+
}
201+
135202
/// Returns the [`Path`] for a given `embedded` asset.
136203
/// This is used internally by [`embedded_asset`] and can be used to get a [`Path`]
137204
/// that matches the [`AssetPath`](crate::AssetPath) used by that asset.
@@ -140,7 +207,7 @@ impl EmbeddedAssetRegistry {
140207
#[macro_export]
141208
macro_rules! embedded_path {
142209
($path_str: expr) => {{
143-
embedded_path!("src", $path_str)
210+
$crate::embedded_path!("src", $path_str)
144211
}};
145212

146213
($source_path: expr, $path_str: expr) => {{
@@ -185,7 +252,7 @@ pub fn _embedded_asset_path(
185252
/// Creates a new `embedded` asset by embedding the bytes of the given path into the current binary
186253
/// and registering those bytes with the `embedded` [`AssetSource`].
187254
///
188-
/// This accepts the current [`App`](bevy_app::App) as the first parameter and a path `&str` (relative to the current file) as the second.
255+
/// This accepts the current [`App`] as the first parameter and a path `&str` (relative to the current file) as the second.
189256
///
190257
/// By default this will generate an [`AssetPath`] using the following rules:
191258
///
@@ -210,14 +277,19 @@ pub fn _embedded_asset_path(
210277
///
211278
/// `embedded_asset!(app, "rock.wgsl")`
212279
///
213-
/// `rock.wgsl` can now be loaded by the [`AssetServer`](crate::AssetServer) with the following path:
280+
/// `rock.wgsl` can now be loaded by the [`AssetServer`] as follows:
214281
///
215282
/// ```no_run
216-
/// # use bevy_asset::{Asset, AssetServer};
283+
/// # use bevy_asset::{Asset, AssetServer, load_embedded_asset};
217284
/// # use bevy_reflect::TypePath;
218285
/// # let asset_server: AssetServer = panic!();
219286
/// # #[derive(Asset, TypePath)]
220287
/// # struct Shader;
288+
/// // If we are loading the shader in the same module we used `embedded_asset!`:
289+
/// let shader = load_embedded_asset!(&asset_server, "rock.wgsl");
290+
/// # let _: bevy_asset::Handle<Shader> = shader;
291+
///
292+
/// // If the goal is to expose the asset **to the end user**:
221293
/// let shader = asset_server.load::<Shader>("embedded://bevy_rock/render/rock.wgsl");
222294
/// ```
223295
///
@@ -251,11 +323,11 @@ pub fn _embedded_asset_path(
251323
/// [`embedded_path`]: crate::embedded_path
252324
#[macro_export]
253325
macro_rules! embedded_asset {
254-
($app: ident, $path: expr) => {{
326+
($app: expr, $path: expr) => {{
255327
$crate::embedded_asset!($app, "src", $path)
256328
}};
257329

258-
($app: ident, $source_path: expr, $path: expr) => {{
330+
($app: expr, $source_path: expr, $path: expr) => {{
259331
let mut embedded = $app
260332
.world_mut()
261333
.resource_mut::<$crate::io::embedded::EmbeddedAssetRegistry>();

crates/bevy_asset/src/path.rs

+10
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,16 @@ impl<'a> AssetPath<'a> {
223223
Ok((source, path, label))
224224
}
225225

226+
/// Creates a new [`AssetPath`] from a [`PathBuf`].
227+
#[inline]
228+
pub fn from_path_buf(path_buf: PathBuf) -> AssetPath<'a> {
229+
AssetPath {
230+
path: CowArc::Owned(path_buf.into()),
231+
source: AssetSourceId::Default,
232+
label: None,
233+
}
234+
}
235+
226236
/// Creates a new [`AssetPath`] from a [`Path`].
227237
#[inline]
228238
pub fn from_path(path: &'a Path) -> AssetPath<'a> {

crates/bevy_pbr/src/deferred/mod.rs

+6-12
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::{
1010
ViewLightsUniformOffset,
1111
};
1212
use bevy_app::prelude::*;
13-
use bevy_asset::{load_internal_asset, weak_handle, Handle};
13+
use bevy_asset::{embedded_asset, load_embedded_asset, Handle};
1414
use bevy_core_pipeline::{
1515
core_3d::graph::{Core3d, Node3d},
1616
deferred::{
@@ -34,9 +34,6 @@ use bevy_render::{
3434

3535
pub struct DeferredPbrLightingPlugin;
3636

37-
pub const DEFERRED_LIGHTING_SHADER_HANDLE: Handle<Shader> =
38-
weak_handle!("f4295279-8890-4748-b654-ca4d2183df1c");
39-
4037
pub const DEFAULT_PBR_DEFERRED_LIGHTING_PASS_ID: u8 = 1;
4138

4239
/// Component with a `depth_id` for specifying which corresponding materials should be rendered by this specific PBR deferred lighting pass.
@@ -100,12 +97,7 @@ impl Plugin for DeferredPbrLightingPlugin {
10097
))
10198
.add_systems(PostUpdate, insert_deferred_lighting_pass_id_component);
10299

103-
load_internal_asset!(
104-
app,
105-
DEFERRED_LIGHTING_SHADER_HANDLE,
106-
"deferred_lighting.wgsl",
107-
Shader::from_wgsl
108-
);
100+
embedded_asset!(app, "deferred_lighting.wgsl");
109101

110102
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
111103
return;
@@ -237,6 +229,7 @@ impl ViewNode for DeferredOpaquePass3dPbrLightingNode {
237229
pub struct DeferredLightingLayout {
238230
mesh_pipeline: MeshPipeline,
239231
bind_group_layout_1: BindGroupLayout,
232+
deferred_lighting_shader: Handle<Shader>,
240233
}
241234

242235
#[derive(Component)]
@@ -360,13 +353,13 @@ impl SpecializedRenderPipeline for DeferredLightingLayout {
360353
self.bind_group_layout_1.clone(),
361354
],
362355
vertex: VertexState {
363-
shader: DEFERRED_LIGHTING_SHADER_HANDLE,
356+
shader: self.deferred_lighting_shader.clone(),
364357
shader_defs: shader_defs.clone(),
365358
entry_point: "vertex".into(),
366359
buffers: Vec::new(),
367360
},
368361
fragment: Some(FragmentState {
369-
shader: DEFERRED_LIGHTING_SHADER_HANDLE,
362+
shader: self.deferred_lighting_shader.clone(),
370363
shader_defs,
371364
entry_point: "fragment".into(),
372365
targets: vec![Some(ColorTargetState {
@@ -416,6 +409,7 @@ impl FromWorld for DeferredLightingLayout {
416409
Self {
417410
mesh_pipeline: world.resource::<MeshPipeline>().clone(),
418411
bind_group_layout_1: layout,
412+
deferred_lighting_shader: load_embedded_asset!(world, "deferred_lighting.wgsl"),
419413
}
420414
}
421415
}

0 commit comments

Comments
 (0)