Path: blob/main/crates/bevy_pbr/src/atmosphere/resources.rs
6604 views
use crate::{GpuLights, LightMeta};1use bevy_asset::{load_embedded_asset, Handle};2use bevy_camera::{Camera, Camera3d};3use bevy_core_pipeline::FullscreenShader;4use bevy_ecs::{5component::Component,6entity::Entity,7query::With,8resource::Resource,9system::{Commands, Query, Res, ResMut},10world::{FromWorld, World},11};12use bevy_image::ToExtents;13use bevy_math::{Affine3A, Mat4, Vec3A};14use bevy_render::{15extract_component::ComponentUniforms,16render_resource::{binding_types::*, *},17renderer::{RenderDevice, RenderQueue},18texture::{CachedTexture, TextureCache},19view::{ExtractedView, Msaa, ViewDepthTexture, ViewUniform, ViewUniforms},20};21use bevy_shader::Shader;22use bevy_utils::default;2324use super::{Atmosphere, GpuAtmosphereSettings};2526#[derive(Resource)]27pub(crate) struct AtmosphereBindGroupLayouts {28pub transmittance_lut: BindGroupLayout,29pub multiscattering_lut: BindGroupLayout,30pub sky_view_lut: BindGroupLayout,31pub aerial_view_lut: BindGroupLayout,32}3334#[derive(Resource)]35pub(crate) struct RenderSkyBindGroupLayouts {36pub render_sky: BindGroupLayout,37pub render_sky_msaa: BindGroupLayout,38pub fullscreen_shader: FullscreenShader,39pub fragment_shader: Handle<Shader>,40}4142impl FromWorld for AtmosphereBindGroupLayouts {43fn from_world(world: &mut World) -> Self {44let render_device = world.resource::<RenderDevice>();45let transmittance_lut = render_device.create_bind_group_layout(46"transmittance_lut_bind_group_layout",47&BindGroupLayoutEntries::with_indices(48ShaderStages::COMPUTE,49(50(0, uniform_buffer::<Atmosphere>(true)),51(1, uniform_buffer::<GpuAtmosphereSettings>(true)),52(53// transmittance lut storage texture5413,55texture_storage_2d(56TextureFormat::Rgba16Float,57StorageTextureAccess::WriteOnly,58),59),60),61),62);6364let multiscattering_lut = render_device.create_bind_group_layout(65"multiscattering_lut_bind_group_layout",66&BindGroupLayoutEntries::with_indices(67ShaderStages::COMPUTE,68(69(0, uniform_buffer::<Atmosphere>(true)),70(1, uniform_buffer::<GpuAtmosphereSettings>(true)),71(5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler72(6, sampler(SamplerBindingType::Filtering)),73(74//multiscattering lut storage texture7513,76texture_storage_2d(77TextureFormat::Rgba16Float,78StorageTextureAccess::WriteOnly,79),80),81),82),83);8485let sky_view_lut = render_device.create_bind_group_layout(86"sky_view_lut_bind_group_layout",87&BindGroupLayoutEntries::with_indices(88ShaderStages::COMPUTE,89(90(0, uniform_buffer::<Atmosphere>(true)),91(1, uniform_buffer::<GpuAtmosphereSettings>(true)),92(2, uniform_buffer::<AtmosphereTransform>(true)),93(3, uniform_buffer::<ViewUniform>(true)),94(4, uniform_buffer::<GpuLights>(true)),95(5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler96(6, sampler(SamplerBindingType::Filtering)),97(7, texture_2d(TextureSampleType::Float { filterable: true })), //multiscattering lut and sampler98(8, sampler(SamplerBindingType::Filtering)),99(10013,101texture_storage_2d(102TextureFormat::Rgba16Float,103StorageTextureAccess::WriteOnly,104),105),106),107),108);109110let aerial_view_lut = render_device.create_bind_group_layout(111"aerial_view_lut_bind_group_layout",112&BindGroupLayoutEntries::with_indices(113ShaderStages::COMPUTE,114(115(0, uniform_buffer::<Atmosphere>(true)),116(1, uniform_buffer::<GpuAtmosphereSettings>(true)),117(3, uniform_buffer::<ViewUniform>(true)),118(4, uniform_buffer::<GpuLights>(true)),119(5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler120(6, sampler(SamplerBindingType::Filtering)),121(7, texture_2d(TextureSampleType::Float { filterable: true })), //multiscattering lut and sampler122(8, sampler(SamplerBindingType::Filtering)),123(124//Aerial view lut storage texture12513,126texture_storage_3d(127TextureFormat::Rgba16Float,128StorageTextureAccess::WriteOnly,129),130),131),132),133);134135Self {136transmittance_lut,137multiscattering_lut,138sky_view_lut,139aerial_view_lut,140}141}142}143144impl FromWorld for RenderSkyBindGroupLayouts {145fn from_world(world: &mut World) -> Self {146let render_device = world.resource::<RenderDevice>();147let render_sky = render_device.create_bind_group_layout(148"render_sky_bind_group_layout",149&BindGroupLayoutEntries::with_indices(150ShaderStages::FRAGMENT,151(152(0, uniform_buffer::<Atmosphere>(true)),153(1, uniform_buffer::<GpuAtmosphereSettings>(true)),154(2, uniform_buffer::<AtmosphereTransform>(true)),155(3, uniform_buffer::<ViewUniform>(true)),156(4, uniform_buffer::<GpuLights>(true)),157(5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler158(6, sampler(SamplerBindingType::Filtering)),159(7, texture_2d(TextureSampleType::Float { filterable: true })), //multiscattering lut and sampler160(8, sampler(SamplerBindingType::Filtering)),161(9, texture_2d(TextureSampleType::Float { filterable: true })), //sky view lut and sampler162(10, sampler(SamplerBindingType::Filtering)),163(164// aerial view lut and sampler16511,166texture_3d(TextureSampleType::Float { filterable: true }),167),168(12, sampler(SamplerBindingType::Filtering)),169(170//view depth texture17113,172texture_2d(TextureSampleType::Depth),173),174),175),176);177178let render_sky_msaa = render_device.create_bind_group_layout(179"render_sky_msaa_bind_group_layout",180&BindGroupLayoutEntries::with_indices(181ShaderStages::FRAGMENT,182(183(0, uniform_buffer::<Atmosphere>(true)),184(1, uniform_buffer::<GpuAtmosphereSettings>(true)),185(2, uniform_buffer::<AtmosphereTransform>(true)),186(3, uniform_buffer::<ViewUniform>(true)),187(4, uniform_buffer::<GpuLights>(true)),188(5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler189(6, sampler(SamplerBindingType::Filtering)),190(7, texture_2d(TextureSampleType::Float { filterable: true })), //multiscattering lut and sampler191(8, sampler(SamplerBindingType::Filtering)),192(9, texture_2d(TextureSampleType::Float { filterable: true })), //sky view lut and sampler193(10, sampler(SamplerBindingType::Filtering)),194(195// aerial view lut and sampler19611,197texture_3d(TextureSampleType::Float { filterable: true }),198),199(12, sampler(SamplerBindingType::Filtering)),200(201//view depth texture20213,203texture_2d_multisampled(TextureSampleType::Depth),204),205),206),207);208209Self {210render_sky,211render_sky_msaa,212fullscreen_shader: world.resource::<FullscreenShader>().clone(),213fragment_shader: load_embedded_asset!(world, "render_sky.wgsl"),214}215}216}217218#[derive(Resource)]219pub struct AtmosphereSamplers {220pub transmittance_lut: Sampler,221pub multiscattering_lut: Sampler,222pub sky_view_lut: Sampler,223pub aerial_view_lut: Sampler,224}225226impl FromWorld for AtmosphereSamplers {227fn from_world(world: &mut World) -> Self {228let render_device = world.resource::<RenderDevice>();229230let base_sampler = SamplerDescriptor {231mag_filter: FilterMode::Linear,232min_filter: FilterMode::Linear,233mipmap_filter: FilterMode::Nearest,234..Default::default()235};236237let transmittance_lut = render_device.create_sampler(&SamplerDescriptor {238label: Some("transmittance_lut_sampler"),239..base_sampler240});241242let multiscattering_lut = render_device.create_sampler(&SamplerDescriptor {243label: Some("multiscattering_lut_sampler"),244..base_sampler245});246247let sky_view_lut = render_device.create_sampler(&SamplerDescriptor {248label: Some("sky_view_lut_sampler"),249address_mode_u: AddressMode::Repeat,250..base_sampler251});252253let aerial_view_lut = render_device.create_sampler(&SamplerDescriptor {254label: Some("aerial_view_lut_sampler"),255..base_sampler256});257258Self {259transmittance_lut,260multiscattering_lut,261sky_view_lut,262aerial_view_lut,263}264}265}266267#[derive(Resource)]268pub(crate) struct AtmosphereLutPipelines {269pub transmittance_lut: CachedComputePipelineId,270pub multiscattering_lut: CachedComputePipelineId,271pub sky_view_lut: CachedComputePipelineId,272pub aerial_view_lut: CachedComputePipelineId,273}274275impl FromWorld for AtmosphereLutPipelines {276fn from_world(world: &mut World) -> Self {277let pipeline_cache = world.resource::<PipelineCache>();278let layouts = world.resource::<AtmosphereBindGroupLayouts>();279280let transmittance_lut = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {281label: Some("transmittance_lut_pipeline".into()),282layout: vec![layouts.transmittance_lut.clone()],283shader: load_embedded_asset!(world, "transmittance_lut.wgsl"),284..default()285});286287let multiscattering_lut =288pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {289label: Some("multi_scattering_lut_pipeline".into()),290layout: vec![layouts.multiscattering_lut.clone()],291shader: load_embedded_asset!(world, "multiscattering_lut.wgsl"),292..default()293});294295let sky_view_lut = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {296label: Some("sky_view_lut_pipeline".into()),297layout: vec![layouts.sky_view_lut.clone()],298shader: load_embedded_asset!(world, "sky_view_lut.wgsl"),299..default()300});301302let aerial_view_lut = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {303label: Some("aerial_view_lut_pipeline".into()),304layout: vec![layouts.aerial_view_lut.clone()],305shader: load_embedded_asset!(world, "aerial_view_lut.wgsl"),306..default()307});308309Self {310transmittance_lut,311multiscattering_lut,312sky_view_lut,313aerial_view_lut,314}315}316}317318#[derive(Component)]319pub(crate) struct RenderSkyPipelineId(pub CachedRenderPipelineId);320321#[derive(Copy, Clone, Hash, PartialEq, Eq)]322pub(crate) struct RenderSkyPipelineKey {323pub msaa_samples: u32,324pub dual_source_blending: bool,325}326327impl SpecializedRenderPipeline for RenderSkyBindGroupLayouts {328type Key = RenderSkyPipelineKey;329330fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {331let mut shader_defs = Vec::new();332333if key.msaa_samples > 1 {334shader_defs.push("MULTISAMPLED".into());335}336if key.dual_source_blending {337shader_defs.push("DUAL_SOURCE_BLENDING".into());338}339340let dst_factor = if key.dual_source_blending {341BlendFactor::Src1342} else {343BlendFactor::SrcAlpha344};345346RenderPipelineDescriptor {347label: Some(format!("render_sky_pipeline_{}", key.msaa_samples).into()),348layout: vec![if key.msaa_samples == 1 {349self.render_sky.clone()350} else {351self.render_sky_msaa.clone()352}],353vertex: self.fullscreen_shader.to_vertex_state(),354fragment: Some(FragmentState {355shader: self.fragment_shader.clone(),356shader_defs,357targets: vec![Some(ColorTargetState {358format: TextureFormat::Rgba16Float,359blend: Some(BlendState {360color: BlendComponent {361src_factor: BlendFactor::One,362dst_factor,363operation: BlendOperation::Add,364},365alpha: BlendComponent {366src_factor: BlendFactor::Zero,367dst_factor: BlendFactor::One,368operation: BlendOperation::Add,369},370}),371write_mask: ColorWrites::ALL,372})],373..default()374}),375multisample: MultisampleState {376count: key.msaa_samples,377..default()378},379..default()380}381}382}383384pub(super) fn queue_render_sky_pipelines(385views: Query<(Entity, &Msaa), (With<Camera>, With<Atmosphere>)>,386pipeline_cache: Res<PipelineCache>,387layouts: Res<RenderSkyBindGroupLayouts>,388mut specializer: ResMut<SpecializedRenderPipelines<RenderSkyBindGroupLayouts>>,389render_device: Res<RenderDevice>,390mut commands: Commands,391) {392for (entity, msaa) in &views {393let id = specializer.specialize(394&pipeline_cache,395&layouts,396RenderSkyPipelineKey {397msaa_samples: msaa.samples(),398dual_source_blending: render_device399.features()400.contains(WgpuFeatures::DUAL_SOURCE_BLENDING),401},402);403commands.entity(entity).insert(RenderSkyPipelineId(id));404}405}406407#[derive(Component)]408pub struct AtmosphereTextures {409pub transmittance_lut: CachedTexture,410pub multiscattering_lut: CachedTexture,411pub sky_view_lut: CachedTexture,412pub aerial_view_lut: CachedTexture,413}414415pub(super) fn prepare_atmosphere_textures(416views: Query<(Entity, &GpuAtmosphereSettings), With<Atmosphere>>,417render_device: Res<RenderDevice>,418mut texture_cache: ResMut<TextureCache>,419mut commands: Commands,420) {421for (entity, lut_settings) in &views {422let transmittance_lut = texture_cache.get(423&render_device,424TextureDescriptor {425label: Some("transmittance_lut"),426size: lut_settings.transmittance_lut_size.to_extents(),427mip_level_count: 1,428sample_count: 1,429dimension: TextureDimension::D2,430format: TextureFormat::Rgba16Float,431usage: TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING,432view_formats: &[],433},434);435436let multiscattering_lut = texture_cache.get(437&render_device,438TextureDescriptor {439label: Some("multiscattering_lut"),440size: lut_settings.multiscattering_lut_size.to_extents(),441mip_level_count: 1,442sample_count: 1,443dimension: TextureDimension::D2,444format: TextureFormat::Rgba16Float,445usage: TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING,446view_formats: &[],447},448);449450let sky_view_lut = texture_cache.get(451&render_device,452TextureDescriptor {453label: Some("sky_view_lut"),454size: lut_settings.sky_view_lut_size.to_extents(),455mip_level_count: 1,456sample_count: 1,457dimension: TextureDimension::D2,458format: TextureFormat::Rgba16Float,459usage: TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING,460view_formats: &[],461},462);463464let aerial_view_lut = texture_cache.get(465&render_device,466TextureDescriptor {467label: Some("aerial_view_lut"),468size: lut_settings.aerial_view_lut_size.to_extents(),469mip_level_count: 1,470sample_count: 1,471dimension: TextureDimension::D3,472format: TextureFormat::Rgba16Float,473usage: TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING,474view_formats: &[],475},476);477478commands.entity(entity).insert({479AtmosphereTextures {480transmittance_lut,481multiscattering_lut,482sky_view_lut,483aerial_view_lut,484}485});486}487}488489#[derive(Resource, Default)]490pub struct AtmosphereTransforms {491uniforms: DynamicUniformBuffer<AtmosphereTransform>,492}493494impl AtmosphereTransforms {495#[inline]496pub fn uniforms(&self) -> &DynamicUniformBuffer<AtmosphereTransform> {497&self.uniforms498}499}500501#[derive(ShaderType)]502pub struct AtmosphereTransform {503world_from_atmosphere: Mat4,504}505506#[derive(Component)]507pub struct AtmosphereTransformsOffset {508index: u32,509}510511impl AtmosphereTransformsOffset {512#[inline]513pub fn index(&self) -> u32 {514self.index515}516}517518pub(super) fn prepare_atmosphere_transforms(519views: Query<(Entity, &ExtractedView), (With<Atmosphere>, With<Camera3d>)>,520render_device: Res<RenderDevice>,521render_queue: Res<RenderQueue>,522mut atmo_uniforms: ResMut<AtmosphereTransforms>,523mut commands: Commands,524) {525let atmo_count = views.iter().len();526let Some(mut writer) =527atmo_uniforms528.uniforms529.get_writer(atmo_count, &render_device, &render_queue)530else {531return;532};533534for (entity, view) in &views {535let world_from_view = view.world_from_view.affine();536let camera_z = world_from_view.matrix3.z_axis;537let camera_y = world_from_view.matrix3.y_axis;538let atmo_z = camera_z539.with_y(0.0)540.try_normalize()541.unwrap_or_else(|| camera_y.with_y(0.0).normalize());542let atmo_y = Vec3A::Y;543let atmo_x = atmo_y.cross(atmo_z).normalize();544let world_from_atmosphere =545Affine3A::from_cols(atmo_x, atmo_y, atmo_z, world_from_view.translation);546547let world_from_atmosphere = Mat4::from(world_from_atmosphere);548549commands.entity(entity).insert(AtmosphereTransformsOffset {550index: writer.write(&AtmosphereTransform {551world_from_atmosphere,552}),553});554}555}556557#[derive(Component)]558pub(crate) struct AtmosphereBindGroups {559pub transmittance_lut: BindGroup,560pub multiscattering_lut: BindGroup,561pub sky_view_lut: BindGroup,562pub aerial_view_lut: BindGroup,563pub render_sky: BindGroup,564}565566pub(super) fn prepare_atmosphere_bind_groups(567views: Query<568(Entity, &AtmosphereTextures, &ViewDepthTexture, &Msaa),569(With<Camera3d>, With<Atmosphere>),570>,571render_device: Res<RenderDevice>,572layouts: Res<AtmosphereBindGroupLayouts>,573render_sky_layouts: Res<RenderSkyBindGroupLayouts>,574samplers: Res<AtmosphereSamplers>,575view_uniforms: Res<ViewUniforms>,576lights_uniforms: Res<LightMeta>,577atmosphere_transforms: Res<AtmosphereTransforms>,578atmosphere_uniforms: Res<ComponentUniforms<Atmosphere>>,579settings_uniforms: Res<ComponentUniforms<GpuAtmosphereSettings>>,580581mut commands: Commands,582) {583if views.iter().len() == 0 {584return;585}586587let atmosphere_binding = atmosphere_uniforms588.binding()589.expect("Failed to prepare atmosphere bind groups. Atmosphere uniform buffer missing");590591let transforms_binding = atmosphere_transforms592.uniforms()593.binding()594.expect("Failed to prepare atmosphere bind groups. Atmosphere transforms buffer missing");595596let settings_binding = settings_uniforms.binding().expect(597"Failed to prepare atmosphere bind groups. AtmosphereSettings uniform buffer missing",598);599600let view_binding = view_uniforms601.uniforms602.binding()603.expect("Failed to prepare atmosphere bind groups. View uniform buffer missing");604605let lights_binding = lights_uniforms606.view_gpu_lights607.binding()608.expect("Failed to prepare atmosphere bind groups. Lights uniform buffer missing");609610for (entity, textures, view_depth_texture, msaa) in &views {611let transmittance_lut = render_device.create_bind_group(612"transmittance_lut_bind_group",613&layouts.transmittance_lut,614&BindGroupEntries::with_indices((615(0, atmosphere_binding.clone()),616(1, settings_binding.clone()),617(13, &textures.transmittance_lut.default_view),618)),619);620621let multiscattering_lut = render_device.create_bind_group(622"multiscattering_lut_bind_group",623&layouts.multiscattering_lut,624&BindGroupEntries::with_indices((625(0, atmosphere_binding.clone()),626(1, settings_binding.clone()),627(5, &textures.transmittance_lut.default_view),628(6, &samplers.transmittance_lut),629(13, &textures.multiscattering_lut.default_view),630)),631);632633let sky_view_lut = render_device.create_bind_group(634"sky_view_lut_bind_group",635&layouts.sky_view_lut,636&BindGroupEntries::with_indices((637(0, atmosphere_binding.clone()),638(1, settings_binding.clone()),639(2, transforms_binding.clone()),640(3, view_binding.clone()),641(4, lights_binding.clone()),642(5, &textures.transmittance_lut.default_view),643(6, &samplers.transmittance_lut),644(7, &textures.multiscattering_lut.default_view),645(8, &samplers.multiscattering_lut),646(13, &textures.sky_view_lut.default_view),647)),648);649650let aerial_view_lut = render_device.create_bind_group(651"sky_view_lut_bind_group",652&layouts.aerial_view_lut,653&BindGroupEntries::with_indices((654(0, atmosphere_binding.clone()),655(1, settings_binding.clone()),656(3, view_binding.clone()),657(4, lights_binding.clone()),658(5, &textures.transmittance_lut.default_view),659(6, &samplers.transmittance_lut),660(7, &textures.multiscattering_lut.default_view),661(8, &samplers.multiscattering_lut),662(13, &textures.aerial_view_lut.default_view),663)),664);665666let render_sky = render_device.create_bind_group(667"render_sky_bind_group",668if *msaa == Msaa::Off {669&render_sky_layouts.render_sky670} else {671&render_sky_layouts.render_sky_msaa672},673&BindGroupEntries::with_indices((674(0, atmosphere_binding.clone()),675(1, settings_binding.clone()),676(2, transforms_binding.clone()),677(3, view_binding.clone()),678(4, lights_binding.clone()),679(5, &textures.transmittance_lut.default_view),680(6, &samplers.transmittance_lut),681(7, &textures.multiscattering_lut.default_view),682(8, &samplers.multiscattering_lut),683(9, &textures.sky_view_lut.default_view),684(10, &samplers.sky_view_lut),685(11, &textures.aerial_view_lut.default_view),686(12, &samplers.aerial_view_lut),687(13, view_depth_texture.view()),688)),689);690691commands.entity(entity).insert(AtmosphereBindGroups {692transmittance_lut,693multiscattering_lut,694sky_view_lut,695aerial_view_lut,696render_sky,697});698}699}700701702