This commit is contained in:
andriyDev 2025-07-18 16:39:58 +00:00 committed by GitHub
commit 322f7c6d6c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 294 additions and 275 deletions

View File

@ -42,8 +42,10 @@ use bevy_core_pipeline::core_3d::graph::Node3d;
use bevy_ecs::{
component::Component,
query::{Changed, QueryItem, With},
schedule::IntoScheduleConfigs,
system::{lifetimeless::Read, Query},
resource::Resource,
schedule::{common_conditions::resource_exists, IntoScheduleConfigs, SystemSet},
system::{lifetimeless::Read, Commands, Query, Res},
world::World,
};
use bevy_math::{UVec2, UVec3, Vec3};
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
@ -52,6 +54,7 @@ use bevy_render::{
load_shader_library,
render_resource::{DownlevelFlags, ShaderType, SpecializedRenderPipelines},
view::Hdr,
RenderStartup,
};
use bevy_render::{
extract_component::{ExtractComponent, ExtractComponentPlugin},
@ -68,12 +71,14 @@ use resources::{
};
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::{
node::{AtmosphereLutsNode, AtmosphereNode, RenderSkyNode},
resources::{
prepare_atmosphere_bind_groups, prepare_atmosphere_textures, AtmosphereBindGroupLayouts,
AtmosphereLutPipelines, AtmosphereSamplers,
},
resources::{prepare_atmosphere_bind_groups, prepare_atmosphere_textures},
};
#[doc(hidden)]
@ -100,40 +105,39 @@ impl Plugin for AtmospherePlugin {
UniformComponentPlugin::<Atmosphere>::default(),
UniformComponentPlugin::<AtmosphereSettings>::default(),
));
}
fn finish(&self, app: &mut App) {
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
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
.init_resource::<AtmosphereBindGroupLayouts>()
.init_resource::<RenderSkyBindGroupLayouts>()
.init_resource::<AtmosphereSamplers>()
.init_resource::<AtmosphereLutPipelines>()
.init_resource::<AtmosphereTransforms>()
.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(
Render,
(
@ -142,36 +146,66 @@ impl Plugin for AtmospherePlugin {
prepare_atmosphere_textures.in_set(RenderSystems::PrepareResources),
prepare_atmosphere_transforms.in_set(RenderSystems::PrepareResources),
prepare_atmosphere_bind_groups.in_set(RenderSystems::PrepareBindGroups),
),
)
.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,
),
)
.in_set(AtmosphereSystems),
);
}
}
#[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
/// will enable atmospheric scattering for that camera. This is only compatible with
/// HDR cameras.

View File

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

View File

@ -24,6 +24,7 @@ The following are the (public) resources that are now initialized in `RenderStar
- `OitBuffers`
- `PostProcessingPipeline`
- `TonemappingPipeline`
- `AtmosphereSamplers`
- `BoxShadowPipeline`
- `GradientPipeline`
- `UiPipeline`