diff --git a/crates/bevy_pbr/src/environment_map/environment_map.wgsl b/crates/bevy_pbr/src/environment_map/environment_map.wgsl index 7e2bc8b3882cf..1c225645a812c 100644 --- a/crates/bevy_pbr/src/environment_map/environment_map.wgsl +++ b/crates/bevy_pbr/src/environment_map/environment_map.wgsl @@ -18,8 +18,9 @@ fn environment_map_light( ) -> EnvironmentMapLight { // Split-sum approximation for image based lighting: https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf - let smallest_specular_mip_level = textureNumLevels(environment_map_specular) - 1i; - let radiance_level = perceptual_roughness * f32(smallest_specular_mip_level); + // Technically we could use textureNumLevels(environment_map_specular) - 1 here, but we use a uniform + // because textureNumLevels() does not work on WebGL2 + let radiance_level = perceptual_roughness * f32(lights.environment_map_smallest_specular_mip_level); let irradiance = textureSample(environment_map_diffuse, environment_map_sampler, N).rgb; let radiance = textureSampleLevel(environment_map_specular, environment_map_sampler, R, radiance_level).rgb; diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 440011ac4a0bf..daa0b5fb57a4f 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -1,9 +1,9 @@ use crate::{ directional_light_order, point_light_order, AmbientLight, Cascade, CascadeShadowConfig, Cascades, CascadesVisibleEntities, Clusters, CubemapVisibleEntities, DirectionalLight, - DirectionalLightShadowMap, DrawMesh, GlobalVisiblePointLights, MeshPipeline, NotShadowCaster, - PointLight, PointLightShadowMap, SetMeshBindGroup, SpotLight, VisiblePointLights, - SHADOW_SHADER_HANDLE, + DirectionalLightShadowMap, DrawMesh, EnvironmentMapLight, GlobalVisiblePointLights, + MeshPipeline, NotShadowCaster, PointLight, PointLightShadowMap, SetMeshBindGroup, SpotLight, + VisiblePointLights, SHADOW_SHADER_HANDLE, }; use bevy_asset::Handle; use bevy_core_pipeline::core_3d::Transparent3d; @@ -218,6 +218,7 @@ pub struct GpuLights { n_directional_lights: u32, // offset from spot light's light index to spot light's shadow map index spot_light_shadowmap_offset: i32, + environment_map_smallest_specular_mip_level: u32, } // NOTE: this must be kept in sync with the same constants in pbr.frag @@ -787,12 +788,18 @@ pub(crate) fn spot_light_projection_matrix(angle: f32) -> Mat4 { pub fn prepare_lights( mut commands: Commands, mut texture_cache: ResMut, + images: Res>, render_device: Res, render_queue: Res, mut global_light_meta: ResMut, mut light_meta: ResMut, views: Query< - (Entity, &ExtractedView, &ExtractedClusterConfig), + ( + Entity, + &ExtractedView, + &ExtractedClusterConfig, + Option<&EnvironmentMapLight>, + ), With>, >, ambient_light: Res, @@ -1029,7 +1036,7 @@ pub fn prepare_lights( .write_buffer(&render_device, &render_queue); // set up light data for each view - for (entity, extracted_view, clusters) in &views { + for (entity, extracted_view, clusters, environment_map) in &views { let point_light_depth_texture = texture_cache.get( &render_device, TextureDescriptor { @@ -1096,6 +1103,10 @@ pub fn prepare_lights( // index to shadow map index, we need to subtract point light count and add directional shadowmap count. spot_light_shadowmap_offset: num_directional_cascades_enabled as i32 - point_light_count as i32, + environment_map_smallest_specular_mip_level: environment_map + .and_then(|env_map| images.get(&env_map.specular_map)) + .map(|specular_map| specular_map.mip_level_count - 1) + .unwrap_or(0), }; // TODO: this should select lights based on relevance to the view instead of the first ones that show up in a query diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 34350740d58cc..48afafd225ccd 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -537,6 +537,7 @@ impl FromWorld for MeshPipeline { image.texture_descriptor.size.width as f32, image.texture_descriptor.size.height as f32, ), + mip_level_count: image.texture_descriptor.mip_level_count, } }; diff --git a/crates/bevy_pbr/src/render/mesh_view_types.wgsl b/crates/bevy_pbr/src/render/mesh_view_types.wgsl index 57ac0cfa27d92..b944aa2792e2f 100644 --- a/crates/bevy_pbr/src/render/mesh_view_types.wgsl +++ b/crates/bevy_pbr/src/render/mesh_view_types.wgsl @@ -24,7 +24,7 @@ struct DirectionalCascade { texel_size: f32, far_bound: f32, } - + struct DirectionalLight { cascades: array, color: vec4, @@ -59,6 +59,7 @@ struct Lights { cluster_factors: vec4, n_directional_lights: u32, spot_light_shadowmap_offset: i32, + environment_map_smallest_specular_mip_level: u32, }; struct Fog { diff --git a/crates/bevy_render/src/texture/fallback_image.rs b/crates/bevy_render/src/texture/fallback_image.rs index d152c07ea4f16..9160dadbac2e6 100644 --- a/crates/bevy_render/src/texture/fallback_image.rs +++ b/crates/bevy_render/src/texture/fallback_image.rs @@ -78,6 +78,7 @@ fn fallback_image_new( image.texture_descriptor.size.width as f32, image.texture_descriptor.size.height as f32, ), + mip_level_count: image.texture_descriptor.mip_level_count, } } diff --git a/crates/bevy_render/src/texture/image.rs b/crates/bevy_render/src/texture/image.rs index 00559bed361ec..bdb02a6d5d552 100644 --- a/crates/bevy_render/src/texture/image.rs +++ b/crates/bevy_render/src/texture/image.rs @@ -494,6 +494,7 @@ pub struct GpuImage { pub texture_format: TextureFormat, pub sampler: Sampler, pub size: Vec2, + pub mip_level_count: u32, } impl RenderAsset for Image { @@ -543,6 +544,7 @@ impl RenderAsset for Image { texture_format: image.texture_descriptor.format, sampler, size, + mip_level_count: image.texture_descriptor.mip_level_count, }) } } diff --git a/crates/bevy_sprite/src/mesh2d/mesh.rs b/crates/bevy_sprite/src/mesh2d/mesh.rs index c46ef1d883669..448ea1aa30711 100644 --- a/crates/bevy_sprite/src/mesh2d/mesh.rs +++ b/crates/bevy_sprite/src/mesh2d/mesh.rs @@ -252,6 +252,7 @@ impl FromWorld for Mesh2dPipeline { image.texture_descriptor.size.width as f32, image.texture_descriptor.size.height as f32, ), + mip_level_count: image.texture_descriptor.mip_level_count, } }; Mesh2dPipeline { diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 301ab2376c552..da553d3674a2c 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -131,6 +131,7 @@ impl FromWorld for SpritePipeline { image.texture_descriptor.size.width as f32, image.texture_descriptor.size.height as f32, ), + mip_level_count: image.texture_descriptor.mip_level_count, } };