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::{
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,15 +105,60 @@ 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>();
render_app
.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,
(
configure_camera_depth_usages.in_set(RenderSystems::ManageViews),
queue_render_sky_pipelines.in_set(RenderSystems::Queue),
prepare_atmosphere_textures.in_set(RenderSystems::PrepareResources),
prepare_atmosphere_transforms.in_set(RenderSystems::PrepareResources),
prepare_atmosphere_bind_groups.in_set(RenderSystems::PrepareBindGroups),
)
.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
@ -127,23 +177,11 @@ impl Plugin for AtmospherePlugin {
return;
}
render_app
.init_resource::<AtmosphereBindGroupLayouts>()
.init_resource::<RenderSkyBindGroupLayouts>()
.init_resource::<AtmosphereSamplers>()
.init_resource::<AtmosphereLutPipelines>()
.init_resource::<AtmosphereTransforms>()
.init_resource::<SpecializedRenderPipelines<RenderSkyBindGroupLayouts>>()
.add_systems(
Render,
(
configure_camera_depth_usages.in_set(RenderSystems::ManageViews),
queue_render_sky_pipelines.in_set(RenderSystems::Queue),
prepare_atmosphere_textures.in_set(RenderSystems::PrepareResources),
prepare_atmosphere_transforms.in_set(RenderSystems::PrepareResources),
prepare_atmosphere_bind_groups.in_set(RenderSystems::PrepareBindGroups),
),
)
commands.insert_resource(AtmosphereSupported);
}
fn add_atmosphere_render_graph_nodes(world: &mut World) {
world
.add_render_graph_node::<ViewNodeRunner<AtmosphereLutsNode>>(
Core3d,
AtmosphereNode::RenderLuts,
@ -157,10 +195,7 @@ impl Plugin for AtmospherePlugin {
Node3d::StartMainPass,
),
)
.add_render_graph_node::<ViewNodeRunner<RenderSkyNode>>(
Core3d,
AtmosphereNode::RenderSky,
)
.add_render_graph_node::<ViewNodeRunner<RenderSkyNode>>(Core3d, AtmosphereNode::RenderSky)
.add_render_graph_edges(
Core3d,
(
@ -169,7 +204,6 @@ impl Plugin for AtmospherePlugin {
Node3d::MainTransparentPass,
),
);
}
}
/// This component describes the atmosphere of a planet, and when added to a camera

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,9 +38,10 @@ 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>();
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(
@ -52,10 +52,7 @@ impl FromWorld for AtmosphereBindGroupLayouts {
(
// transmittance lut storage texture
13,
texture_storage_2d(
TextureFormat::Rgba16Float,
StorageTextureAccess::WriteOnly,
),
texture_storage_2d(TextureFormat::Rgba16Float, StorageTextureAccess::WriteOnly),
),
),
),
@ -73,10 +70,7 @@ impl FromWorld for AtmosphereBindGroupLayouts {
(
//multiscattering lut storage texture
13,
texture_storage_2d(
TextureFormat::Rgba16Float,
StorageTextureAccess::WriteOnly,
),
texture_storage_2d(TextureFormat::Rgba16Float, StorageTextureAccess::WriteOnly),
),
),
),
@ -98,10 +92,7 @@ impl FromWorld for AtmosphereBindGroupLayouts {
(8, sampler(SamplerBindingType::Filtering)),
(
13,
texture_storage_2d(
TextureFormat::Rgba16Float,
StorageTextureAccess::WriteOnly,
),
texture_storage_2d(TextureFormat::Rgba16Float, StorageTextureAccess::WriteOnly),
),
),
),
@ -123,27 +114,26 @@ impl FromWorld for AtmosphereBindGroupLayouts {
(
//Aerial view lut storage texture
13,
texture_storage_3d(
TextureFormat::Rgba16Float,
StorageTextureAccess::WriteOnly,
),
texture_storage_3d(TextureFormat::Rgba16Float, StorageTextureAccess::WriteOnly),
),
),
),
);
Self {
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>();
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(
@ -202,13 +192,12 @@ impl FromWorld for RenderSkyBindGroupLayouts {
),
);
Self {
commands.insert_resource(RenderSkyBindGroupLayouts {
render_sky,
render_sky_msaa,
fullscreen_shader: world.resource::<FullscreenShader>().clone(),
fragment_shader: load_embedded_asset!(world, "render_sky.wgsl"),
}
}
fullscreen_shader: fullscreen_shader.clone(),
fragment_shader: load_embedded_asset!(asset_server.as_ref(), "render_sky.wgsl"),
});
}
#[derive(Resource)]
@ -219,10 +208,7 @@ 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,
@ -251,13 +237,12 @@ impl FromWorld for AtmosphereSamplers {
..base_sampler
});
Self {
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!(world, "transmittance_lut.wgsl"),
shader: load_embedded_asset!(asset_server.as_ref(), "transmittance_lut.wgsl"),
..default()
});
let multiscattering_lut =
pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
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"),
shader: load_embedded_asset!(asset_server.as_ref(), "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!(world, "sky_view_lut.wgsl"),
shader: load_embedded_asset!(asset_server.as_ref(), "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!(world, "aerial_view_lut.wgsl"),
shader: load_embedded_asset!(asset_server.as_ref(), "aerial_view_lut.wgsl"),
..default()
});
Self {
commands.insert_resource(AtmosphereLutPipelines {
transmittance_lut,
multiscattering_lut,
sky_view_lut,
aerial_view_lut,
}
}
});
}
#[derive(Component)]