Use RenderStartup for atmosphere rendering.

This commit is contained in:
andriyDev 2025-07-18 01:12:55 -07:00
parent 877d278785
commit 1c5ee801ae
2 changed files with 293 additions and 275 deletions

View File

@ -42,8 +42,10 @@ use bevy_core_pipeline::core_3d::graph::Node3d;
use bevy_ecs::{ use bevy_ecs::{
component::Component, component::Component,
query::{Changed, QueryItem, With}, query::{Changed, QueryItem, With},
schedule::IntoScheduleConfigs, resource::Resource,
system::{lifetimeless::Read, Query}, schedule::{common_conditions::resource_exists, IntoScheduleConfigs, SystemSet},
system::{lifetimeless::Read, Commands, Query, Res},
world::World,
}; };
use bevy_math::{UVec2, UVec3, Vec3}; use bevy_math::{UVec2, UVec3, Vec3};
use bevy_reflect::{std_traits::ReflectDefault, Reflect}; use bevy_reflect::{std_traits::ReflectDefault, Reflect};
@ -52,6 +54,7 @@ use bevy_render::{
load_shader_library, load_shader_library,
render_resource::{DownlevelFlags, ShaderType, SpecializedRenderPipelines}, render_resource::{DownlevelFlags, ShaderType, SpecializedRenderPipelines},
view::Hdr, view::Hdr,
RenderStartup,
}; };
use bevy_render::{ use bevy_render::{
extract_component::{ExtractComponent, ExtractComponentPlugin}, extract_component::{ExtractComponent, ExtractComponentPlugin},
@ -68,12 +71,14 @@ use resources::{
}; };
use tracing::warn; use tracing::warn;
use crate::resources::{
init_atmosphere_bind_group_layouts, init_atmosphere_lut_pipelines, init_atmosphere_samplers,
init_render_sky_bind_group_layouts,
};
use self::{ use self::{
node::{AtmosphereLutsNode, AtmosphereNode, RenderSkyNode}, node::{AtmosphereLutsNode, AtmosphereNode, RenderSkyNode},
resources::{ resources::{prepare_atmosphere_bind_groups, prepare_atmosphere_textures},
prepare_atmosphere_bind_groups, prepare_atmosphere_textures, AtmosphereBindGroupLayouts,
AtmosphereLutPipelines, AtmosphereSamplers,
},
}; };
#[doc(hidden)] #[doc(hidden)]
@ -100,40 +105,39 @@ impl Plugin for AtmospherePlugin {
UniformComponentPlugin::<Atmosphere>::default(), UniformComponentPlugin::<Atmosphere>::default(),
UniformComponentPlugin::<AtmosphereSettings>::default(), UniformComponentPlugin::<AtmosphereSettings>::default(),
)); ));
}
fn finish(&self, app: &mut App) {
let Some(render_app) = app.get_sub_app_mut(RenderApp) else { let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
return; return;
}; };
let render_adapter = render_app.world().resource::<RenderAdapter>();
if !render_adapter
.get_downlevel_capabilities()
.flags
.contains(DownlevelFlags::COMPUTE_SHADERS)
{
warn!("AtmospherePlugin not loaded. GPU lacks support for compute shaders.");
return;
}
if !render_adapter
.get_texture_format_features(TextureFormat::Rgba16Float)
.allowed_usages
.contains(TextureUsages::STORAGE_BINDING)
{
warn!("AtmospherePlugin not loaded. GPU lacks support: TextureFormat::Rgba16Float does not support TextureUsages::STORAGE_BINDING.");
return;
}
render_app render_app
.init_resource::<AtmosphereBindGroupLayouts>()
.init_resource::<RenderSkyBindGroupLayouts>()
.init_resource::<AtmosphereSamplers>()
.init_resource::<AtmosphereLutPipelines>()
.init_resource::<AtmosphereTransforms>() .init_resource::<AtmosphereTransforms>()
.init_resource::<SpecializedRenderPipelines<RenderSkyBindGroupLayouts>>() .init_resource::<SpecializedRenderPipelines<RenderSkyBindGroupLayouts>>()
.configure_sets(
RenderStartup,
AtmosphereSystems
.after(check_atmosphere_supported)
.run_if(resource_exists::<AtmosphereSupported>),
)
.configure_sets(
Render,
AtmosphereSystems.run_if(resource_exists::<AtmosphereSupported>),
)
.add_systems(RenderStartup, check_atmosphere_supported)
.add_systems(
RenderStartup,
(
add_atmosphere_render_graph_nodes,
init_render_sky_bind_group_layouts,
init_atmosphere_samplers,
(
init_atmosphere_bind_group_layouts,
init_atmosphere_lut_pipelines,
)
.chain(),
)
.in_set(AtmosphereSystems),
)
.add_systems( .add_systems(
Render, Render,
( (
@ -142,36 +146,66 @@ impl Plugin for AtmospherePlugin {
prepare_atmosphere_textures.in_set(RenderSystems::PrepareResources), prepare_atmosphere_textures.in_set(RenderSystems::PrepareResources),
prepare_atmosphere_transforms.in_set(RenderSystems::PrepareResources), prepare_atmosphere_transforms.in_set(RenderSystems::PrepareResources),
prepare_atmosphere_bind_groups.in_set(RenderSystems::PrepareBindGroups), prepare_atmosphere_bind_groups.in_set(RenderSystems::PrepareBindGroups),
), )
) .in_set(AtmosphereSystems),
.add_render_graph_node::<ViewNodeRunner<AtmosphereLutsNode>>(
Core3d,
AtmosphereNode::RenderLuts,
)
.add_render_graph_edges(
Core3d,
(
// END_PRE_PASSES -> RENDER_LUTS -> MAIN_PASS
Node3d::EndPrepasses,
AtmosphereNode::RenderLuts,
Node3d::StartMainPass,
),
)
.add_render_graph_node::<ViewNodeRunner<RenderSkyNode>>(
Core3d,
AtmosphereNode::RenderSky,
)
.add_render_graph_edges(
Core3d,
(
Node3d::MainOpaquePass,
AtmosphereNode::RenderSky,
Node3d::MainTransparentPass,
),
); );
} }
} }
#[derive(SystemSet, Hash, PartialEq, Eq, Clone, Debug)]
struct AtmosphereSystems;
#[derive(Resource)]
struct AtmosphereSupported;
fn check_atmosphere_supported(mut commands: Commands, render_adapter: Res<RenderAdapter>) {
if !render_adapter
.get_downlevel_capabilities()
.flags
.contains(DownlevelFlags::COMPUTE_SHADERS)
{
warn!("AtmospherePlugin not loaded. GPU lacks support for compute shaders.");
return;
}
if !render_adapter
.get_texture_format_features(TextureFormat::Rgba16Float)
.allowed_usages
.contains(TextureUsages::STORAGE_BINDING)
{
warn!("AtmospherePlugin not loaded. GPU lacks support: TextureFormat::Rgba16Float does not support TextureUsages::STORAGE_BINDING.");
return;
}
commands.insert_resource(AtmosphereSupported);
}
fn add_atmosphere_render_graph_nodes(world: &mut World) {
world
.add_render_graph_node::<ViewNodeRunner<AtmosphereLutsNode>>(
Core3d,
AtmosphereNode::RenderLuts,
)
.add_render_graph_edges(
Core3d,
(
// END_PRE_PASSES -> RENDER_LUTS -> MAIN_PASS
Node3d::EndPrepasses,
AtmosphereNode::RenderLuts,
Node3d::StartMainPass,
),
)
.add_render_graph_node::<ViewNodeRunner<RenderSkyNode>>(Core3d, AtmosphereNode::RenderSky)
.add_render_graph_edges(
Core3d,
(
Node3d::MainOpaquePass,
AtmosphereNode::RenderSky,
Node3d::MainTransparentPass,
),
);
}
/// This component describes the atmosphere of a planet, and when added to a camera /// This component describes the atmosphere of a planet, and when added to a camera
/// will enable atmospheric scattering for that camera. This is only compatible with /// will enable atmospheric scattering for that camera. This is only compatible with
/// HDR cameras. /// HDR cameras.

View File

@ -1,5 +1,5 @@
use crate::{GpuLights, LightMeta}; use crate::{GpuLights, LightMeta};
use bevy_asset::{load_embedded_asset, Handle}; use bevy_asset::{load_embedded_asset, AssetServer, Handle};
use bevy_core_pipeline::{core_3d::Camera3d, FullscreenShader}; use bevy_core_pipeline::{core_3d::Camera3d, FullscreenShader};
use bevy_ecs::{ use bevy_ecs::{
component::Component, component::Component,
@ -7,7 +7,6 @@ use bevy_ecs::{
query::With, query::With,
resource::Resource, resource::Resource,
system::{Commands, Query, Res, ResMut}, system::{Commands, Query, Res, ResMut},
world::{FromWorld, World},
}; };
use bevy_image::ToExtents; use bevy_image::ToExtents;
use bevy_math::{Mat4, Vec3}; use bevy_math::{Mat4, Vec3};
@ -39,176 +38,166 @@ pub(crate) struct RenderSkyBindGroupLayouts {
pub fragment_shader: Handle<Shader>, pub fragment_shader: Handle<Shader>,
} }
impl FromWorld for AtmosphereBindGroupLayouts { pub(crate) fn init_atmosphere_bind_group_layouts(
fn from_world(world: &mut World) -> Self { mut commands: Commands,
let render_device = world.resource::<RenderDevice>(); render_device: Res<RenderDevice>,
let transmittance_lut = render_device.create_bind_group_layout( ) {
"transmittance_lut_bind_group_layout", let transmittance_lut = render_device.create_bind_group_layout(
&BindGroupLayoutEntries::with_indices( "transmittance_lut_bind_group_layout",
ShaderStages::COMPUTE, &BindGroupLayoutEntries::with_indices(
ShaderStages::COMPUTE,
(
(0, uniform_buffer::<Atmosphere>(true)),
(1, uniform_buffer::<AtmosphereSettings>(true)),
( (
(0, uniform_buffer::<Atmosphere>(true)), // transmittance lut storage texture
(1, uniform_buffer::<AtmosphereSettings>(true)), 13,
( texture_storage_2d(TextureFormat::Rgba16Float, StorageTextureAccess::WriteOnly),
// transmittance lut storage texture
13,
texture_storage_2d(
TextureFormat::Rgba16Float,
StorageTextureAccess::WriteOnly,
),
),
), ),
), ),
); ),
);
let multiscattering_lut = render_device.create_bind_group_layout( let multiscattering_lut = render_device.create_bind_group_layout(
"multiscattering_lut_bind_group_layout", "multiscattering_lut_bind_group_layout",
&BindGroupLayoutEntries::with_indices( &BindGroupLayoutEntries::with_indices(
ShaderStages::COMPUTE, ShaderStages::COMPUTE,
(
(0, uniform_buffer::<Atmosphere>(true)),
(1, uniform_buffer::<AtmosphereSettings>(true)),
(5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler
(6, sampler(SamplerBindingType::Filtering)),
( (
(0, uniform_buffer::<Atmosphere>(true)), //multiscattering lut storage texture
(1, uniform_buffer::<AtmosphereSettings>(true)), 13,
(5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler texture_storage_2d(TextureFormat::Rgba16Float, StorageTextureAccess::WriteOnly),
(6, sampler(SamplerBindingType::Filtering)),
(
//multiscattering lut storage texture
13,
texture_storage_2d(
TextureFormat::Rgba16Float,
StorageTextureAccess::WriteOnly,
),
),
), ),
), ),
); ),
);
let sky_view_lut = render_device.create_bind_group_layout( let sky_view_lut = render_device.create_bind_group_layout(
"sky_view_lut_bind_group_layout", "sky_view_lut_bind_group_layout",
&BindGroupLayoutEntries::with_indices( &BindGroupLayoutEntries::with_indices(
ShaderStages::COMPUTE, ShaderStages::COMPUTE,
(
(0, uniform_buffer::<Atmosphere>(true)),
(1, uniform_buffer::<AtmosphereSettings>(true)),
(2, uniform_buffer::<AtmosphereTransform>(true)),
(3, uniform_buffer::<ViewUniform>(true)),
(4, uniform_buffer::<GpuLights>(true)),
(5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler
(6, sampler(SamplerBindingType::Filtering)),
(7, texture_2d(TextureSampleType::Float { filterable: true })), //multiscattering lut and sampler
(8, sampler(SamplerBindingType::Filtering)),
( (
(0, uniform_buffer::<Atmosphere>(true)), 13,
(1, uniform_buffer::<AtmosphereSettings>(true)), texture_storage_2d(TextureFormat::Rgba16Float, StorageTextureAccess::WriteOnly),
(2, uniform_buffer::<AtmosphereTransform>(true)),
(3, uniform_buffer::<ViewUniform>(true)),
(4, uniform_buffer::<GpuLights>(true)),
(5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler
(6, sampler(SamplerBindingType::Filtering)),
(7, texture_2d(TextureSampleType::Float { filterable: true })), //multiscattering lut and sampler
(8, sampler(SamplerBindingType::Filtering)),
(
13,
texture_storage_2d(
TextureFormat::Rgba16Float,
StorageTextureAccess::WriteOnly,
),
),
), ),
), ),
); ),
);
let aerial_view_lut = render_device.create_bind_group_layout( let aerial_view_lut = render_device.create_bind_group_layout(
"aerial_view_lut_bind_group_layout", "aerial_view_lut_bind_group_layout",
&BindGroupLayoutEntries::with_indices( &BindGroupLayoutEntries::with_indices(
ShaderStages::COMPUTE, ShaderStages::COMPUTE,
(
(0, uniform_buffer::<Atmosphere>(true)),
(1, uniform_buffer::<AtmosphereSettings>(true)),
(3, uniform_buffer::<ViewUniform>(true)),
(4, uniform_buffer::<GpuLights>(true)),
(5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler
(6, sampler(SamplerBindingType::Filtering)),
(7, texture_2d(TextureSampleType::Float { filterable: true })), //multiscattering lut and sampler
(8, sampler(SamplerBindingType::Filtering)),
( (
(0, uniform_buffer::<Atmosphere>(true)), //Aerial view lut storage texture
(1, uniform_buffer::<AtmosphereSettings>(true)), 13,
(3, uniform_buffer::<ViewUniform>(true)), texture_storage_3d(TextureFormat::Rgba16Float, StorageTextureAccess::WriteOnly),
(4, uniform_buffer::<GpuLights>(true)),
(5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler
(6, sampler(SamplerBindingType::Filtering)),
(7, texture_2d(TextureSampleType::Float { filterable: true })), //multiscattering lut and sampler
(8, sampler(SamplerBindingType::Filtering)),
(
//Aerial view lut storage texture
13,
texture_storage_3d(
TextureFormat::Rgba16Float,
StorageTextureAccess::WriteOnly,
),
),
), ),
), ),
); ),
);
Self { commands.insert_resource(AtmosphereBindGroupLayouts {
transmittance_lut, transmittance_lut,
multiscattering_lut, multiscattering_lut,
sky_view_lut, sky_view_lut,
aerial_view_lut, aerial_view_lut,
} });
}
} }
impl FromWorld for RenderSkyBindGroupLayouts { pub(crate) fn init_render_sky_bind_group_layouts(
fn from_world(world: &mut World) -> Self { mut commands: Commands,
let render_device = world.resource::<RenderDevice>(); render_device: Res<RenderDevice>,
let render_sky = render_device.create_bind_group_layout( fullscreen_shader: Res<FullscreenShader>,
"render_sky_bind_group_layout", asset_server: Res<AssetServer>,
&BindGroupLayoutEntries::with_indices( ) {
ShaderStages::FRAGMENT, let render_sky = render_device.create_bind_group_layout(
"render_sky_bind_group_layout",
&BindGroupLayoutEntries::with_indices(
ShaderStages::FRAGMENT,
(
(0, uniform_buffer::<Atmosphere>(true)),
(1, uniform_buffer::<AtmosphereSettings>(true)),
(2, uniform_buffer::<AtmosphereTransform>(true)),
(3, uniform_buffer::<ViewUniform>(true)),
(4, uniform_buffer::<GpuLights>(true)),
(5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler
(6, sampler(SamplerBindingType::Filtering)),
(9, texture_2d(TextureSampleType::Float { filterable: true })), //sky view lut and sampler
(10, sampler(SamplerBindingType::Filtering)),
( (
(0, uniform_buffer::<Atmosphere>(true)), // aerial view lut and sampler
(1, uniform_buffer::<AtmosphereSettings>(true)), 11,
(2, uniform_buffer::<AtmosphereTransform>(true)), texture_3d(TextureSampleType::Float { filterable: true }),
(3, uniform_buffer::<ViewUniform>(true)), ),
(4, uniform_buffer::<GpuLights>(true)), (12, sampler(SamplerBindingType::Filtering)),
(5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler (
(6, sampler(SamplerBindingType::Filtering)), //view depth texture
(9, texture_2d(TextureSampleType::Float { filterable: true })), //sky view lut and sampler 13,
(10, sampler(SamplerBindingType::Filtering)), texture_2d(TextureSampleType::Depth),
(
// aerial view lut and sampler
11,
texture_3d(TextureSampleType::Float { filterable: true }),
),
(12, sampler(SamplerBindingType::Filtering)),
(
//view depth texture
13,
texture_2d(TextureSampleType::Depth),
),
), ),
), ),
); ),
);
let render_sky_msaa = render_device.create_bind_group_layout( let render_sky_msaa = render_device.create_bind_group_layout(
"render_sky_msaa_bind_group_layout", "render_sky_msaa_bind_group_layout",
&BindGroupLayoutEntries::with_indices( &BindGroupLayoutEntries::with_indices(
ShaderStages::FRAGMENT, ShaderStages::FRAGMENT,
(
(0, uniform_buffer::<Atmosphere>(true)),
(1, uniform_buffer::<AtmosphereSettings>(true)),
(2, uniform_buffer::<AtmosphereTransform>(true)),
(3, uniform_buffer::<ViewUniform>(true)),
(4, uniform_buffer::<GpuLights>(true)),
(5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler
(6, sampler(SamplerBindingType::Filtering)),
(9, texture_2d(TextureSampleType::Float { filterable: true })), //sky view lut and sampler
(10, sampler(SamplerBindingType::Filtering)),
( (
(0, uniform_buffer::<Atmosphere>(true)), // aerial view lut and sampler
(1, uniform_buffer::<AtmosphereSettings>(true)), 11,
(2, uniform_buffer::<AtmosphereTransform>(true)), texture_3d(TextureSampleType::Float { filterable: true }),
(3, uniform_buffer::<ViewUniform>(true)), ),
(4, uniform_buffer::<GpuLights>(true)), (12, sampler(SamplerBindingType::Filtering)),
(5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler (
(6, sampler(SamplerBindingType::Filtering)), //view depth texture
(9, texture_2d(TextureSampleType::Float { filterable: true })), //sky view lut and sampler 13,
(10, sampler(SamplerBindingType::Filtering)), texture_2d_multisampled(TextureSampleType::Depth),
(
// aerial view lut and sampler
11,
texture_3d(TextureSampleType::Float { filterable: true }),
),
(12, sampler(SamplerBindingType::Filtering)),
(
//view depth texture
13,
texture_2d_multisampled(TextureSampleType::Depth),
),
), ),
), ),
); ),
);
Self { commands.insert_resource(RenderSkyBindGroupLayouts {
render_sky, render_sky,
render_sky_msaa, render_sky_msaa,
fullscreen_shader: world.resource::<FullscreenShader>().clone(), fullscreen_shader: fullscreen_shader.clone(),
fragment_shader: load_embedded_asset!(world, "render_sky.wgsl"), fragment_shader: load_embedded_asset!(asset_server.as_ref(), "render_sky.wgsl"),
} });
}
} }
#[derive(Resource)] #[derive(Resource)]
@ -219,45 +208,41 @@ pub struct AtmosphereSamplers {
pub aerial_view_lut: Sampler, pub aerial_view_lut: Sampler,
} }
impl FromWorld for AtmosphereSamplers { pub fn init_atmosphere_samplers(mut commands: Commands, render_device: Res<RenderDevice>) {
fn from_world(world: &mut World) -> Self { let base_sampler = SamplerDescriptor {
let render_device = world.resource::<RenderDevice>(); mag_filter: FilterMode::Linear,
min_filter: FilterMode::Linear,
mipmap_filter: FilterMode::Nearest,
..Default::default()
};
let base_sampler = SamplerDescriptor { let transmittance_lut = render_device.create_sampler(&SamplerDescriptor {
mag_filter: FilterMode::Linear, label: Some("transmittance_lut_sampler"),
min_filter: FilterMode::Linear, ..base_sampler
mipmap_filter: FilterMode::Nearest, });
..Default::default()
};
let transmittance_lut = render_device.create_sampler(&SamplerDescriptor { let multiscattering_lut = render_device.create_sampler(&SamplerDescriptor {
label: Some("transmittance_lut_sampler"), label: Some("multiscattering_lut_sampler"),
..base_sampler ..base_sampler
}); });
let multiscattering_lut = render_device.create_sampler(&SamplerDescriptor { let sky_view_lut = render_device.create_sampler(&SamplerDescriptor {
label: Some("multiscattering_lut_sampler"), label: Some("sky_view_lut_sampler"),
..base_sampler address_mode_u: AddressMode::Repeat,
}); ..base_sampler
});
let sky_view_lut = render_device.create_sampler(&SamplerDescriptor { let aerial_view_lut = render_device.create_sampler(&SamplerDescriptor {
label: Some("sky_view_lut_sampler"), label: Some("aerial_view_lut_sampler"),
address_mode_u: AddressMode::Repeat, ..base_sampler
..base_sampler });
});
let aerial_view_lut = render_device.create_sampler(&SamplerDescriptor { commands.insert_resource(AtmosphereSamplers {
label: Some("aerial_view_lut_sampler"), transmittance_lut,
..base_sampler multiscattering_lut,
}); sky_view_lut,
aerial_view_lut,
Self { });
transmittance_lut,
multiscattering_lut,
sky_view_lut,
aerial_view_lut,
}
}
} }
#[derive(Resource)] #[derive(Resource)]
@ -268,47 +253,46 @@ pub(crate) struct AtmosphereLutPipelines {
pub aerial_view_lut: CachedComputePipelineId, pub aerial_view_lut: CachedComputePipelineId,
} }
impl FromWorld for AtmosphereLutPipelines { pub(crate) fn init_atmosphere_lut_pipelines(
fn from_world(world: &mut World) -> Self { mut commands: Commands,
let pipeline_cache = world.resource::<PipelineCache>(); pipeline_cache: Res<PipelineCache>,
let layouts = world.resource::<AtmosphereBindGroupLayouts>(); layouts: Res<AtmosphereBindGroupLayouts>,
asset_server: Res<AssetServer>,
) {
let transmittance_lut = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
label: Some("transmittance_lut_pipeline".into()),
layout: vec![layouts.transmittance_lut.clone()],
shader: load_embedded_asset!(asset_server.as_ref(), "transmittance_lut.wgsl"),
..default()
});
let transmittance_lut = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor { let multiscattering_lut = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
label: Some("transmittance_lut_pipeline".into()), label: Some("multi_scattering_lut_pipeline".into()),
layout: vec![layouts.transmittance_lut.clone()], layout: vec![layouts.multiscattering_lut.clone()],
shader: load_embedded_asset!(world, "transmittance_lut.wgsl"), shader: load_embedded_asset!(asset_server.as_ref(), "multiscattering_lut.wgsl"),
..default() ..default()
}); });
let multiscattering_lut = let sky_view_lut = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor { label: Some("sky_view_lut_pipeline".into()),
label: Some("multi_scattering_lut_pipeline".into()), layout: vec![layouts.sky_view_lut.clone()],
layout: vec![layouts.multiscattering_lut.clone()], shader: load_embedded_asset!(asset_server.as_ref(), "sky_view_lut.wgsl"),
shader: load_embedded_asset!(world, "multiscattering_lut.wgsl"), ..default()
..default() });
});
let sky_view_lut = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor { let aerial_view_lut = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
label: Some("sky_view_lut_pipeline".into()), label: Some("aerial_view_lut_pipeline".into()),
layout: vec![layouts.sky_view_lut.clone()], layout: vec![layouts.aerial_view_lut.clone()],
shader: load_embedded_asset!(world, "sky_view_lut.wgsl"), shader: load_embedded_asset!(asset_server.as_ref(), "aerial_view_lut.wgsl"),
..default() ..default()
}); });
let aerial_view_lut = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor { commands.insert_resource(AtmosphereLutPipelines {
label: Some("aerial_view_lut_pipeline".into()), transmittance_lut,
layout: vec![layouts.aerial_view_lut.clone()], multiscattering_lut,
shader: load_embedded_asset!(world, "aerial_view_lut.wgsl"), sky_view_lut,
..default() aerial_view_lut,
}); });
Self {
transmittance_lut,
multiscattering_lut,
sky_view_lut,
aerial_view_lut,
}
}
} }
#[derive(Component)] #[derive(Component)]