bevy/crates/bevy_pbr/src/atmosphere/render_sky.wgsl
Máté Homolya a616ffa8ac
Web support for atmosphere (#18582)
# Objective

Add web support to atmosphere by gating dual source blending and using a
macro to determine the target platform.
The main objective of this PR is to ensure that users of Bevy's
atmosphere feature can also run it in a web-based context where WebGPU
support is enabled.

## Solution

- Make use of the `#[cfg(not(target_arch = "wasm32"))]` macro to gate
the dual source blending, as this is not (yet) supported in web
browsers.
- Rename the function `sample_sun_illuminance` to `sample_sun_radiance`
and move calls out of conditionals to ensure the shader compiles and
runs in both native and web-based contexts.
- Moved the multiplication of the transmittance out when calculating the
sun color, because calling the `sample_sun_illuminance` function was
causing issues in web. Overall this results in cleaner code and more
readable.

## Testing

- Tested by building a wasm target and loading it in a web page with
Vite dev server using `mate-h/bevy-webgpu` repo template.
- Tested the native build with `cargo run --example atmosphere` to
ensure it still works with dual source blending.

---

## Showcase

Screenshots show the atmosphere example running in two different
contexts:

<img width="1281" alt="atmosphere-web-showcase"
src="https://github.com/user-attachments/assets/40b1ee91-89ae-41a6-8189-89630d1ca1a6"
/>

---------

Co-authored-by: JMS55 <47158642+JMS55@users.noreply.github.com>
2025-04-06 20:06:55 +00:00

59 lines
2.0 KiB
WebGPU Shading Language

#import bevy_pbr::atmosphere::{
types::{Atmosphere, AtmosphereSettings},
bindings::{atmosphere, view, atmosphere_transforms},
functions::{
sample_transmittance_lut, sample_transmittance_lut_segment,
sample_sky_view_lut, direction_world_to_atmosphere,
uv_to_ray_direction, uv_to_ndc, sample_aerial_view_lut,
view_radius, sample_sun_radiance, ndc_to_camera_dist
},
};
#import bevy_render::view::View;
#import bevy_core_pipeline::fullscreen_vertex_shader::FullscreenVertexOutput
#ifdef MULTISAMPLED
@group(0) @binding(13) var depth_texture: texture_depth_multisampled_2d;
#else
@group(0) @binding(13) var depth_texture: texture_depth_2d;
#endif
struct RenderSkyOutput {
@location(0) inscattering: vec4<f32>,
#ifdef DUAL_SOURCE_BLENDING
@location(0) @second_blend_source transmittance: vec4<f32>,
#endif
}
@fragment
fn main(in: FullscreenVertexOutput) -> RenderSkyOutput {
let depth = textureLoad(depth_texture, vec2<i32>(in.position.xy), 0);
let ray_dir_ws = uv_to_ray_direction(in.uv);
let r = view_radius();
let mu = ray_dir_ws.y;
var transmittance: vec3<f32>;
var inscattering: vec3<f32>;
let sun_radiance = sample_sun_radiance(ray_dir_ws.xyz);
if depth == 0.0 {
let ray_dir_as = direction_world_to_atmosphere(ray_dir_ws.xyz);
transmittance = sample_transmittance_lut(r, mu);
inscattering += sample_sky_view_lut(r, ray_dir_as);
inscattering += sun_radiance * transmittance * view.exposure;
} else {
let t = ndc_to_camera_dist(vec3(uv_to_ndc(in.uv), depth));
inscattering = sample_aerial_view_lut(in.uv, t);
transmittance = sample_transmittance_lut_segment(r, mu, t);
}
#ifdef DUAL_SOURCE_BLENDING
return RenderSkyOutput(vec4(inscattering, 0.0), vec4(transmittance, 1.0));
#else
let mean_transmittance = (transmittance.r + transmittance.g + transmittance.b) / 3.0;
return RenderSkyOutput(vec4(inscattering, mean_transmittance));
#endif
}