From fe4f9a815e9c9b63bf52f17e6a6f3e29bdaa10ea Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Fri, 17 Feb 2023 23:47:56 -0500 Subject: [PATCH 1/2] Fallback environment map shader for webgl --- .../src/environment_map/environment_map.wgsl | 4 +++ crates/bevy_pbr/src/render/light.rs | 27 +++++++++++++++++-- crates/bevy_pbr/src/render/mesh.rs | 4 +++ .../bevy_pbr/src/render/mesh_view_types.wgsl | 5 +++- .../bevy_render/src/texture/fallback_image.rs | 1 + crates/bevy_render/src/texture/image.rs | 2 ++ crates/bevy_sprite/src/mesh2d/mesh.rs | 1 + crates/bevy_sprite/src/render/mod.rs | 1 + 8 files changed, 42 insertions(+), 3 deletions(-) diff --git a/crates/bevy_pbr/src/environment_map/environment_map.wgsl b/crates/bevy_pbr/src/environment_map/environment_map.wgsl index 7e2bc8b3882cf..9701957bdc990 100644 --- a/crates/bevy_pbr/src/environment_map/environment_map.wgsl +++ b/crates/bevy_pbr/src/environment_map/environment_map.wgsl @@ -18,7 +18,11 @@ fn environment_map_light( ) -> EnvironmentMapLight { // Split-sum approximation for image based lighting: https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf +#ifndef WEBGL let smallest_specular_mip_level = textureNumLevels(environment_map_specular) - 1i; +#else + let smallest_specular_mip_level = lights.environment_map_smallest_specular_mip_level; +#endif let radiance_level = perceptual_roughness * f32(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..5ddaf52015939 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -218,6 +218,9 @@ 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, + // textureNumLevels() is not supported on WebGL2 + #[cfg(feature = "webgl")] + environment_map_smallest_specular_mip_level: i32, } // NOTE: this must be kept in sync with the same constants in pbr.frag @@ -787,14 +790,24 @@ pub(crate) fn spot_light_projection_matrix(angle: f32) -> Mat4 { pub fn prepare_lights( mut commands: Commands, mut texture_cache: ResMut, + #[cfg(feature = "webgl")] images: Res>, render_device: Res, render_queue: Res, mut global_light_meta: ResMut, mut light_meta: ResMut, - views: Query< + #[cfg(not(feature = "webgl"))] views: Query< (Entity, &ExtractedView, &ExtractedClusterConfig), With>, >, + #[cfg(feature = "webgl")] views: Query< + ( + Entity, + &ExtractedView, + &ExtractedClusterConfig, + Option<&crate::EnvironmentMapLight>, + ), + With>, + >, ambient_light: Res, point_light_shadow_map: Res, directional_light_shadow_map: Res, @@ -1029,7 +1042,12 @@ 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 view in &views { + #[cfg(not(feature = "webgl"))] + let (entity, extracted_view, clusters) = view; + #[cfg(feature = "webgl")] + let (entity, extracted_view, clusters, environment_map) = view; + let point_light_depth_texture = texture_cache.get( &render_device, TextureDescriptor { @@ -1096,6 +1114,11 @@ 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, + #[cfg(feature = "webgl")] + 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 as i32 - 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..ff59823412f76 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, } }; @@ -651,6 +652,9 @@ impl SpecializedMeshPipeline for MeshPipeline { let mut shader_defs = Vec::new(); let mut vertex_attributes = Vec::new(); + #[cfg(feature = "webgl")] + shader_defs.push("WEBGL".into()); + if layout.contains(Mesh::ATTRIBUTE_POSITION) { shader_defs.push("VERTEX_POSITIONS".into()); vertex_attributes.push(Mesh::ATTRIBUTE_POSITION.at_shader_location(0)); diff --git a/crates/bevy_pbr/src/render/mesh_view_types.wgsl b/crates/bevy_pbr/src/render/mesh_view_types.wgsl index 57ac0cfa27d92..da703906b994d 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,9 @@ struct Lights { cluster_factors: vec4, n_directional_lights: u32, spot_light_shadowmap_offset: i32, +#ifdef WEBGL + environment_map_smallest_specular_mip_level: i32, +#endif }; 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, } }; From 97a7c0942fa860685d3521bd7a1e42eec2e6d9a0 Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Sun, 19 Feb 2023 12:57:07 -0500 Subject: [PATCH 2/2] Always use uniform, even on desktop platforms --- .../src/environment_map/environment_map.wgsl | 9 ++---- crates/bevy_pbr/src/render/light.rs | 30 ++++++------------- crates/bevy_pbr/src/render/mesh.rs | 3 -- .../bevy_pbr/src/render/mesh_view_types.wgsl | 4 +-- 4 files changed, 13 insertions(+), 33 deletions(-) diff --git a/crates/bevy_pbr/src/environment_map/environment_map.wgsl b/crates/bevy_pbr/src/environment_map/environment_map.wgsl index 9701957bdc990..1c225645a812c 100644 --- a/crates/bevy_pbr/src/environment_map/environment_map.wgsl +++ b/crates/bevy_pbr/src/environment_map/environment_map.wgsl @@ -18,12 +18,9 @@ fn environment_map_light( ) -> EnvironmentMapLight { // Split-sum approximation for image based lighting: https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf -#ifndef WEBGL - let smallest_specular_mip_level = textureNumLevels(environment_map_specular) - 1i; -#else - let smallest_specular_mip_level = lights.environment_map_smallest_specular_mip_level; -#endif - 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 5ddaf52015939..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,9 +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, - // textureNumLevels() is not supported on WebGL2 - #[cfg(feature = "webgl")] - environment_map_smallest_specular_mip_level: i32, + environment_map_smallest_specular_mip_level: u32, } // NOTE: this must be kept in sync with the same constants in pbr.frag @@ -790,21 +788,17 @@ pub(crate) fn spot_light_projection_matrix(angle: f32) -> Mat4 { pub fn prepare_lights( mut commands: Commands, mut texture_cache: ResMut, - #[cfg(feature = "webgl")] images: Res>, + images: Res>, render_device: Res, render_queue: Res, mut global_light_meta: ResMut, mut light_meta: ResMut, - #[cfg(not(feature = "webgl"))] views: Query< - (Entity, &ExtractedView, &ExtractedClusterConfig), - With>, - >, - #[cfg(feature = "webgl")] views: Query< + views: Query< ( Entity, &ExtractedView, &ExtractedClusterConfig, - Option<&crate::EnvironmentMapLight>, + Option<&EnvironmentMapLight>, ), With>, >, @@ -1042,12 +1036,7 @@ pub fn prepare_lights( .write_buffer(&render_device, &render_queue); // set up light data for each view - for view in &views { - #[cfg(not(feature = "webgl"))] - let (entity, extracted_view, clusters) = view; - #[cfg(feature = "webgl")] - let (entity, extracted_view, clusters, environment_map) = view; - + for (entity, extracted_view, clusters, environment_map) in &views { let point_light_depth_texture = texture_cache.get( &render_device, TextureDescriptor { @@ -1114,10 +1103,9 @@ 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, - #[cfg(feature = "webgl")] 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 as i32 - 1) + .map(|specular_map| specular_map.mip_level_count - 1) .unwrap_or(0), }; diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index ff59823412f76..48afafd225ccd 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -652,9 +652,6 @@ impl SpecializedMeshPipeline for MeshPipeline { let mut shader_defs = Vec::new(); let mut vertex_attributes = Vec::new(); - #[cfg(feature = "webgl")] - shader_defs.push("WEBGL".into()); - if layout.contains(Mesh::ATTRIBUTE_POSITION) { shader_defs.push("VERTEX_POSITIONS".into()); vertex_attributes.push(Mesh::ATTRIBUTE_POSITION.at_shader_location(0)); diff --git a/crates/bevy_pbr/src/render/mesh_view_types.wgsl b/crates/bevy_pbr/src/render/mesh_view_types.wgsl index da703906b994d..b944aa2792e2f 100644 --- a/crates/bevy_pbr/src/render/mesh_view_types.wgsl +++ b/crates/bevy_pbr/src/render/mesh_view_types.wgsl @@ -59,9 +59,7 @@ struct Lights { cluster_factors: vec4, n_directional_lights: u32, spot_light_shadowmap_offset: i32, -#ifdef WEBGL - environment_map_smallest_specular_mip_level: i32, -#endif + environment_map_smallest_specular_mip_level: u32, }; struct Fog {