bevy/crates/bevy_pbr/src/render/fog.wgsl

70 lines
2.2 KiB
WebGPU Shading Language
Raw Normal View History

Add Distance and Atmospheric Fog support (#6412) <img width="1392" alt="image" src="https://user-images.githubusercontent.com/418473/203873533-44c029af-13b7-4740-8ea3-af96bd5867c9.png"> <img width="1392" alt="image" src="https://user-images.githubusercontent.com/418473/203873549-36be7a23-b341-42a2-8a9f-ceea8ac7a2b8.png"> # Objective - Add support for the “classic” distance fog effect, as well as a more advanced atmospheric fog effect. ## Solution This PR: - Introduces a new `FogSettings` component that controls distance fog per-camera. - Adds support for three widely used “traditional” fog falloff modes: `Linear`, `Exponential` and `ExponentialSquared`, as well as a more advanced `Atmospheric` fog; - Adds support for directional light influence over fog color; - Extracts fog via `ExtractComponent`, then uses a prepare system that sets up a new dynamic uniform struct (`Fog`), similar to other mesh view types; - Renders fog in PBR material shader, as a final adjustment to the `output_color`, after PBR is computed (but before tone mapping); - Adds a new `StandardMaterial` flag to enable fog; (`fog_enabled`) - Adds convenience methods for easier artistic control when creating non-linear fog types; - Adds documentation around fog. --- ## Changelog ### Added - Added support for distance-based fog effects for PBR materials, controllable per-camera via the new `FogSettings` component; - Added `FogFalloff` enum for selecting between three widely used “traditional” fog falloff modes: `Linear`, `Exponential` and `ExponentialSquared`, as well as a more advanced `Atmospheric` fog;
2023-01-29 15:28:56 +00:00
#define_import_path bevy_pbr::fog
// Fog formulas adapted from:
// https://learn.microsoft.com/en-us/windows/win32/direct3d9/fog-formulas
// https://catlikecoding.com/unity/tutorials/rendering/part-14/
// https://iquilezles.org/articles/fog/ (Atmospheric Fog and Scattering)
fn scattering_adjusted_fog_color(
scattering: vec3<f32>,
) -> vec4<f32> {
if (fog.directional_light_color.a > 0.0) {
return vec4<f32>(
fog.base_color.rgb
+ scattering * fog.directional_light_color.rgb * fog.directional_light_color.a,
fog.base_color.a,
);
} else {
return fog.base_color;
}
}
fn linear_fog(
input_color: vec4<f32>,
distance: f32,
scattering: vec3<f32>,
) -> vec4<f32> {
var fog_color = scattering_adjusted_fog_color(scattering);
let start = fog.be.x;
let end = fog.be.y;
fog_color.a *= 1.0 - clamp((end - distance) / (end - start), 0.0, 1.0);
return vec4<f32>(mix(input_color.rgb, fog_color.rgb, fog_color.a), input_color.a);
}
fn exponential_fog(
input_color: vec4<f32>,
distance: f32,
scattering: vec3<f32>,
) -> vec4<f32> {
var fog_color = scattering_adjusted_fog_color(scattering);
let density = fog.be.x;
fog_color.a *= 1.0 - 1.0 / exp(distance * density);
return vec4<f32>(mix(input_color.rgb, fog_color.rgb, fog_color.a), input_color.a);
}
fn exponential_squared_fog(
input_color: vec4<f32>,
distance: f32,
scattering: vec3<f32>,
) -> vec4<f32> {
var fog_color = scattering_adjusted_fog_color(scattering);
let distance_times_density = distance * fog.be.x;
fog_color.a *= 1.0 - 1.0 / exp(distance_times_density * distance_times_density);
return vec4<f32>(mix(input_color.rgb, fog_color.rgb, fog_color.a), input_color.a);
}
fn atmospheric_fog(
input_color: vec4<f32>,
distance: f32,
scattering: vec3<f32>,
) -> vec4<f32> {
var fog_color = scattering_adjusted_fog_color(scattering);
let extinction_factor = 1.0 - 1.0 / exp(distance * fog.be);
let inscattering_factor = 1.0 - 1.0 / exp(distance * fog.bi);
return vec4<f32>(
input_color.rgb * (1.0 - extinction_factor * fog_color.a)
+ fog_color.rgb * inscattering_factor * fog_color.a,
input_color.a
);
}