diff --git a/crates/bevy_pbr/src/atmosphere/bindings.wgsl b/crates/bevy_pbr/src/atmosphere/bindings.wgsl index e9bdf6a434005..dcbb5c3b345b4 100644 --- a/crates/bevy_pbr/src/atmosphere/bindings.wgsl +++ b/crates/bevy_pbr/src/atmosphere/bindings.wgsl @@ -7,21 +7,21 @@ atmosphere::types::{Atmosphere, AtmosphereSettings, AtmosphereTransforms} } -@group(0) @binding(0) var atmosphere: Atmosphere; -@group(0) @binding(1) var settings: AtmosphereSettings; -@group(0) @binding(2) var atmosphere_transforms: AtmosphereTransforms; -@group(0) @binding(3) var view: View; -@group(0) @binding(4) var lights: Lights; -@group(0) @binding(5) var transmittance_lut: texture_2d; -@group(0) @binding(6) var transmittance_lut_sampler: sampler; -@group(0) @binding(7) var multiscattering_lut: texture_2d; -@group(0) @binding(8) var multiscattering_lut_sampler: sampler; -@group(0) @binding(9) var sky_view_lut: texture_2d; -@group(0) @binding(10) var sky_view_lut_sampler: sampler; -@group(0) @binding(11) var aerial_view_lut: texture_3d; -@group(0) @binding(12) var aerial_view_lut_sampler: sampler; -@group(0) @binding(14) var directional_shadow_texture: texture_depth_2d_array; -@group(0) @binding(15) var directional_shadow_sampler: sampler_comparison; -@group(0) @binding(16) var blue_noise_texture: texture_2d_array; -@group(0) @binding(17) var blue_noise_sampler: sampler; -@group(0) @binding(18) var probe_transform_buffer: mat4x4; \ No newline at end of file +@group(1) @binding(0) var atmosphere: Atmosphere; +@group(1) @binding(1) var settings: AtmosphereSettings; +@group(1) @binding(2) var atmosphere_transforms: AtmosphereTransforms; +@group(1) @binding(3) var view: View; +@group(1) @binding(4) var lights: Lights; +@group(1) @binding(5) var transmittance_lut: texture_2d; +@group(1) @binding(6) var transmittance_lut_sampler: sampler; +@group(1) @binding(7) var multiscattering_lut: texture_2d; +@group(1) @binding(8) var multiscattering_lut_sampler: sampler; +@group(1) @binding(9) var sky_view_lut: texture_2d; +@group(1) @binding(10) var sky_view_lut_sampler: sampler; +@group(1) @binding(11) var aerial_view_lut: texture_3d; +@group(1) @binding(12) var aerial_view_lut_sampler: sampler; +@group(1) @binding(14) var directional_shadow_texture: texture_depth_2d_array; +@group(1) @binding(15) var directional_shadow_sampler: sampler_comparison; +@group(1) @binding(16) var blue_noise_texture: texture_2d_array; +@group(1) @binding(17) var blue_noise_sampler: sampler; +@group(1) @binding(18) var probe_transform_buffer: mat4x4; \ No newline at end of file diff --git a/crates/bevy_pbr/src/atmosphere/functions.wgsl b/crates/bevy_pbr/src/atmosphere/functions.wgsl index 1b4d93e7afe33..78ae0ec7600e0 100644 --- a/crates/bevy_pbr/src/atmosphere/functions.wgsl +++ b/crates/bevy_pbr/src/atmosphere/functions.wgsl @@ -1,7 +1,7 @@ #define_import_path bevy_pbr::atmosphere::functions #import bevy_render::maths::{PI, HALF_PI, PI_2, fast_acos, fast_acos_4, fast_atan2} - +#import bevy_pbr::shadows #import bevy_pbr::atmosphere::{ types::Atmosphere, bindings::{ @@ -14,9 +14,6 @@ transmittance_lut_r_mu_to_uv, transmittance_lut_uv_to_r_mu, ray_intersects_ground, distance_to_top_atmosphere_boundary, distance_to_bottom_atmosphere_boundary - }, - shadows::{ - get_shadow } } @@ -246,6 +243,21 @@ fn sample_atmosphere(r: f32) -> AtmosphereSample { return sample; } +fn get_shadow(light_index: u32, P: vec3, ray_dir: vec3) -> f32 { + // For raymarched volumes, we can use the ray direction as the normal + // since we don't have surface normals + let world_normal = -ray_dir; // Point against ray direction + let world_pos = vec4((P + vec3(0.0, -atmosphere.bottom_radius, 0.0)) / settings.scene_units_to_m, 1.0); + + // Get view space Z coordinate for cascade selection + let view_pos = view.view_from_world * world_pos; + let view_z = view_pos.z; + + // Assuming we're using the first directional light (index 0) + let light = &lights.directional_lights[light_index]; + return shadows::fetch_directional_shadow(light_index, world_pos, world_normal, view_z); +} + /// evaluates L_scat, equation 3 in the paper, which gives the total single-order scattering towards the view at a single point fn sample_local_inscattering(local_atmosphere: AtmosphereSample, ray_dir: vec3, world_pos: vec3, shadow: bool) -> vec3 { let local_r = length(world_pos); diff --git a/crates/bevy_pbr/src/atmosphere/mod.rs b/crates/bevy_pbr/src/atmosphere/mod.rs index bbcb8d5ae81c5..4d424432ef2cd 100644 --- a/crates/bevy_pbr/src/atmosphere/mod.rs +++ b/crates/bevy_pbr/src/atmosphere/mod.rs @@ -45,7 +45,7 @@ use bevy_ecs::{ schedule::IntoScheduleConfigs, system::Query, }; -use bevy_light::{DirectionalLight}; +use bevy_light::DirectionalLight; use bevy_math::{UVec2, UVec3, Vec3}; use bevy_reflect::{std_traits::ReflectDefault, Reflect}; use bevy_render::{ @@ -66,7 +66,7 @@ use bevy_core_pipeline::core_3d::{graph::Core3d, Camera3d}; use bevy_transform::components::Transform; use resources::{ prepare_atmosphere_transforms, queue_render_sky_pipelines, AtmosphereTransforms, - RenderSkyBindGroupLayouts, + RenderSkyPipeline, }; use tracing::warn; @@ -138,11 +138,11 @@ impl Plugin for AtmospherePlugin { render_app .init_resource::() - .init_resource::() + .init_resource::() .init_resource::() .init_resource::() .init_resource::() - .init_resource::>() + .init_resource::>() .init_resource::() .add_systems( Render, diff --git a/crates/bevy_pbr/src/atmosphere/node.rs b/crates/bevy_pbr/src/atmosphere/node.rs index 1a97e49b1a488..f178d3ab50fe1 100644 --- a/crates/bevy_pbr/src/atmosphere/node.rs +++ b/crates/bevy_pbr/src/atmosphere/node.rs @@ -12,7 +12,11 @@ use bevy_render::{ view::{ViewTarget, ViewUniformOffset}, }; -use crate::{resources::{AtmosphereEnvironmentMap, AtmosphereProbeBindGroups}, ViewLightsUniformOffset}; +use crate::{ + resources::{AtmosphereEnvironmentMap, AtmosphereProbeBindGroups}, + MeshViewBindGroup, ViewEnvironmentMapUniformOffset, ViewFogUniformOffset, + ViewLightProbesUniformOffset, ViewLightsUniformOffset, ViewScreenSpaceReflectionsUniformOffset, +}; use super::{ resources::{ @@ -92,7 +96,7 @@ impl ViewNode for AtmosphereLutsNode { luts_pass.set_pipeline(transmittance_lut_pipeline); luts_pass.set_bind_group( - 0, + 1, &bind_groups.transmittance_lut, &[ atmosphere_uniforms_offset.index(), @@ -106,7 +110,7 @@ impl ViewNode for AtmosphereLutsNode { luts_pass.set_pipeline(multiscattering_lut_pipeline); luts_pass.set_bind_group( - 0, + 1, &bind_groups.multiscattering_lut, &[ atmosphere_uniforms_offset.index(), @@ -124,7 +128,7 @@ impl ViewNode for AtmosphereLutsNode { luts_pass.set_pipeline(sky_view_lut_pipeline); luts_pass.set_bind_group( - 0, + 1, &bind_groups.sky_view_lut, &[ atmosphere_uniforms_offset.index(), @@ -141,7 +145,7 @@ impl ViewNode for AtmosphereLutsNode { luts_pass.set_pipeline(aerial_view_lut_pipeline); luts_pass.set_bind_group( - 0, + 1, &bind_groups.aerial_view_lut, &[ atmosphere_uniforms_offset.index(), @@ -171,6 +175,13 @@ impl ViewNode for RenderSkyNode { Read, Read, Read, + Read, + Read, + Read, + Read, + Read, + Read, + Read, ); fn run<'w>( @@ -186,6 +197,13 @@ impl ViewNode for RenderSkyNode { view_uniforms_offset, lights_uniforms_offset, render_sky_pipeline_id, + view_bind_group, + view_uniform_offset, + view_lights_offset, + view_fog_offset, + view_light_probes_offset, + view_ssr_offset, + view_environment_map_offset, ): QueryItem<'w, '_, Self::ViewQuery>, world: &'w World, ) -> Result<(), NodeRunError> { @@ -210,6 +228,18 @@ impl ViewNode for RenderSkyNode { render_sky_pass.set_pipeline(render_sky_pipeline); render_sky_pass.set_bind_group( 0, + &view_bind_group.main, + &[ + view_uniform_offset.offset, + view_lights_offset.offset, + view_fog_offset.offset, + **view_light_probes_offset, + **view_ssr_offset, + **view_environment_map_offset, + ], + ); + render_sky_pass.set_bind_group( + 1, &atmosphere_bind_groups.render_sky, &[ atmosphere_uniforms_offset.index(), @@ -291,7 +321,7 @@ impl Node for EnvironmentNode { pass.set_pipeline(environment_pipeline); pass.set_bind_group( - 0, + 1, &bind_groups.environment, &[ atmosphere_uniforms_offset.index(), diff --git a/crates/bevy_pbr/src/atmosphere/resources.rs b/crates/bevy_pbr/src/atmosphere/resources.rs index 7e7d1d34720d9..ca4cc784c4f84 100644 --- a/crates/bevy_pbr/src/atmosphere/resources.rs +++ b/crates/bevy_pbr/src/atmosphere/resources.rs @@ -1,9 +1,13 @@ use crate::{ - atmosphere::AtmosphereGlobalTransform, Bluenoise, GpuLights, LightMeta, ShadowSamplers, - ViewShadowBindings, + atmosphere::AtmosphereGlobalTransform, Bluenoise, GpuLights, LightMeta, MeshPipeline, + MeshPipelineViewLayoutKey, MeshPipelineViewLayouts, ShadowSamplers, ViewShadowBindings, }; use bevy_asset::{load_embedded_asset, Assets, Handle, RenderAssetUsages}; +use bevy_core_pipeline::prepass::{ + DeferredPrepass, DepthPrepass, MotionVectorPrepass, NormalPrepass, +}; use bevy_core_pipeline::{core_3d::Camera3d, FullscreenShader}; +use bevy_ecs::query::Has; use bevy_ecs::{ component::Component, entity::Entity, @@ -38,11 +42,12 @@ pub(crate) struct AtmosphereBindGroupLayouts { } #[derive(Resource)] -pub(crate) struct RenderSkyBindGroupLayouts { +pub(crate) struct RenderSkyPipeline { pub render_sky: BindGroupLayout, pub render_sky_msaa: BindGroupLayout, pub fullscreen_shader: FullscreenShader, pub fragment_shader: Handle, + pub mesh_view_layouts: MeshPipelineViewLayouts, } impl FromWorld for AtmosphereBindGroupLayouts { @@ -198,7 +203,7 @@ impl FromWorld for AtmosphereBindGroupLayouts { } } -impl FromWorld for RenderSkyBindGroupLayouts { +impl FromWorld for RenderSkyPipeline { fn from_world(world: &mut World) -> Self { let render_device = world.resource::(); let render_sky = render_device.create_bind_group_layout( @@ -272,6 +277,7 @@ impl FromWorld for RenderSkyBindGroupLayouts { render_sky_msaa, fullscreen_shader: world.resource::().clone(), fragment_shader: load_embedded_asset!(world, "render_sky.wgsl"), + mesh_view_layouts: world.resource::().clone(), } } } @@ -402,9 +408,10 @@ pub(crate) struct RenderSkyPipelineId(pub CachedRenderPipelineId); pub(crate) struct RenderSkyPipelineKey { pub msaa_samples: u32, pub dual_source_blending: bool, + pub mesh_pipeline_view_key: MeshPipelineViewLayoutKey, } -impl SpecializedRenderPipeline for RenderSkyBindGroupLayouts { +impl SpecializedRenderPipeline for RenderSkyPipeline { type Key = RenderSkyPipelineKey; fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor { @@ -423,13 +430,23 @@ impl SpecializedRenderPipeline for RenderSkyBindGroupLayouts { BlendFactor::SrcAlpha }; + let render_sky_bind_group_layout = if key.msaa_samples == 1 { + self.render_sky.clone() + } else { + self.render_sky_msaa.clone() + }; + + let layout = self + .mesh_view_layouts + .get_view_layout(key.mesh_pipeline_view_key); + let layout = vec![ + layout.main_layout.clone(), + render_sky_bind_group_layout.clone(), + ]; + RenderPipelineDescriptor { label: Some(format!("render_sky_pipeline_{}", key.msaa_samples).into()), - layout: vec![if key.msaa_samples == 1 { - self.render_sky.clone() - } else { - self.render_sky_msaa.clone() - }], + layout, vertex: self.fullscreen_shader.to_vertex_state(), fragment: Some(FragmentState { shader: self.fragment_shader.clone(), @@ -462,14 +479,40 @@ impl SpecializedRenderPipeline for RenderSkyBindGroupLayouts { } pub(super) fn queue_render_sky_pipelines( - views: Query<(Entity, &Msaa), (With, With)>, + views: Query< + ( + Entity, + &Msaa, + Has, + Has, + Has, + Has, + ), + (With, With), + >, pipeline_cache: Res, - layouts: Res, - mut specializer: ResMut>, + layouts: Res, + mut specializer: ResMut>, render_device: Res, + _mesh_pipeline: Res, mut commands: Commands, ) { - for (entity, msaa) in &views { + for (entity, msaa, normal_prepass, depth_prepass, motion_vector_prepass, deferred_prepass) in + &views + { + let mut mesh_pipeline_view_key = MeshPipelineViewLayoutKey::from(*msaa); + mesh_pipeline_view_key.set(MeshPipelineViewLayoutKey::NORMAL_PREPASS, normal_prepass); + mesh_pipeline_view_key.set(MeshPipelineViewLayoutKey::DEPTH_PREPASS, depth_prepass); + mesh_pipeline_view_key.set( + MeshPipelineViewLayoutKey::MOTION_VECTOR_PREPASS, + motion_vector_prepass, + ); + mesh_pipeline_view_key.set( + MeshPipelineViewLayoutKey::DEFERRED_PREPASS, + deferred_prepass, + ); + mesh_pipeline_view_key.set(MeshPipelineViewLayoutKey::ATMOSPHERE, true); + let id = specializer.specialize( &pipeline_cache, &layouts, @@ -478,6 +521,7 @@ pub(super) fn queue_render_sky_pipelines( dual_source_blending: render_device .features() .contains(WgpuFeatures::DUAL_SOURCE_BLENDING), + mesh_pipeline_view_key, }, ); commands.entity(entity).insert(RenderSkyPipelineId(id)); @@ -723,7 +767,7 @@ pub(super) fn prepare_atmosphere_bind_groups( render_device: Res, queue: Res, layouts: Res, - render_sky_layouts: Res, + render_sky_layouts: Res, samplers: Res, view_uniforms: Res, lights_uniforms: Res, @@ -920,14 +964,14 @@ pub(super) fn prepare_atmosphere_bind_groups( #[derive(ShaderType)] #[repr(C)] -pub(crate) struct PbrAtmosphereData { +pub(crate) struct AtmosphereData { pub atmosphere: Atmosphere, pub settings: AtmosphereSettings, } #[derive(Resource)] pub struct AtmosphereBuffer { - pub(crate) buffer: StorageBuffer, + pub(crate) buffer: StorageBuffer, } impl FromWorld for AtmosphereBuffer { @@ -937,11 +981,11 @@ impl FromWorld for AtmosphereBuffer { .iter(world) .next() .map_or_else( - || PbrAtmosphereData { + || AtmosphereData { atmosphere: Atmosphere::default(), settings: AtmosphereSettings::default(), }, - |(atmosphere, settings)| PbrAtmosphereData { + |(atmosphere, settings)| AtmosphereData { atmosphere: atmosphere.clone(), settings: settings.clone(), }, @@ -963,7 +1007,7 @@ pub(crate) fn prepare_atmosphere_buffer( return; }; - atmosphere_buffer.buffer.set(PbrAtmosphereData { + atmosphere_buffer.buffer.set(AtmosphereData { atmosphere: atmosphere.clone(), settings: settings.clone(), }); @@ -971,12 +1015,7 @@ pub(crate) fn prepare_atmosphere_buffer( } pub fn prepare_atmosphere_probe_components( - probes: Query< - (Entity, &AtmosphereEnvironmentMapLight), - ( - Without, - ), - >, + probes: Query<(Entity, &AtmosphereEnvironmentMapLight), (Without,)>, mut commands: Commands, mut images: ResMut>, ) { diff --git a/crates/bevy_pbr/src/atmosphere/types.wgsl b/crates/bevy_pbr/src/atmosphere/types.wgsl index c373d8a9ae9d4..8a467334c87a2 100644 --- a/crates/bevy_pbr/src/atmosphere/types.wgsl +++ b/crates/bevy_pbr/src/atmosphere/types.wgsl @@ -48,7 +48,7 @@ struct AtmosphereTransforms { atmosphere_from_world: mat4x4, } -struct PbrAtmosphereData { +struct AtmosphereData { atmosphere: Atmosphere, settings: AtmosphereSettings, } \ No newline at end of file diff --git a/crates/bevy_pbr/src/render/mesh_view_bindings.rs b/crates/bevy_pbr/src/render/mesh_view_bindings.rs index 63ee98714d2c7..303eab3aa4fa0 100644 --- a/crates/bevy_pbr/src/render/mesh_view_bindings.rs +++ b/crates/bevy_pbr/src/render/mesh_view_bindings.rs @@ -45,7 +45,7 @@ use crate::{ IRRADIANCE_VOLUMES_ARE_USABLE, }, prepass, - resources::{AtmosphereBuffer, AtmosphereSamplers, AtmosphereTextures, PbrAtmosphereData}, + resources::{AtmosphereBuffer, AtmosphereData, AtmosphereSamplers, AtmosphereTextures}, Atmosphere, EnvironmentMapUniformBuffer, FogMeta, GlobalClusterableObjectMeta, GpuClusterableObjects, GpuFog, GpuLights, LightMeta, LightProbesBuffer, LightProbesUniform, MeshPipeline, MeshPipelineKey, RenderViewLightProbes, ScreenSpaceAmbientOcclusionResources, @@ -407,7 +407,7 @@ fn layout_entries( ), (30, sampler(SamplerBindingType::Filtering)), // atmosphere data buffer - (31, storage_buffer_read_only::(false)), + (31, storage_buffer_read_only::(false)), )); } diff --git a/crates/bevy_pbr/src/render/mesh_view_bindings.wgsl b/crates/bevy_pbr/src/render/mesh_view_bindings.wgsl index 0e120920290b0..5aef30ba05637 100644 --- a/crates/bevy_pbr/src/render/mesh_view_bindings.wgsl +++ b/crates/bevy_pbr/src/render/mesh_view_bindings.wgsl @@ -98,7 +98,7 @@ const VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE: u32 = 64u; #ifdef ATMOSPHERE @group(0) @binding(29) var atmosphere_transmittance_texture: texture_2d; @group(0) @binding(30) var atmosphere_transmittance_sampler: sampler; -@group(0) @binding(31) var atmosphere_data: atmosphere::PbrAtmosphereData; +@group(0) @binding(31) var atmosphere_data: atmosphere::AtmosphereData; #endif // ATMOSPHERE #ifdef MULTIPLE_LIGHT_PROBES_IN_ARRAY