1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477
use crate::ReflectComponent;
use bevy_ecs::prelude::*;
use bevy_math::Vec3;
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
use bevy_render::{color::Color, extract_component::ExtractComponent, prelude::Camera};
/// Configures the “classic” computer graphics [distance fog](https://en.wikipedia.org/wiki/Distance_fog) effect,
/// in which objects appear progressively more covered in atmospheric haze the further away they are from the camera.
/// Affects meshes rendered via the PBR [`StandardMaterial`](crate::StandardMaterial).
///
/// ## Falloff
///
/// The rate at which fog intensity increases with distance is controlled by the falloff mode.
/// Currently, the following fog falloff modes are supported:
///
/// - [`FogFalloff::Linear`]
/// - [`FogFalloff::Exponential`]
/// - [`FogFalloff::ExponentialSquared`]
/// - [`FogFalloff::Atmospheric`]
///
/// ## Example
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # use bevy_render::prelude::*;
/// # use bevy_core_pipeline::prelude::*;
/// # use bevy_pbr::prelude::*;
/// # fn system(mut commands: Commands) {
/// commands.spawn((
/// // Setup your camera as usual
/// Camera3dBundle {
/// // ... camera options
/// # ..Default::default()
/// },
/// // Add fog to the same entity
/// FogSettings {
/// color: Color::WHITE,
/// falloff: FogFalloff::Exponential { density: 1e-3 },
/// ..Default::default()
/// },
/// ));
/// # }
/// # bevy_ecs::system::assert_is_system(system);
/// ```
///
/// ## Material Override
///
/// Once enabled for a specific camera, the fog effect can also be disabled for individual
/// [`StandardMaterial`](crate::StandardMaterial) instances via the `fog_enabled` flag.
#[derive(Debug, Clone, Component, Reflect, ExtractComponent)]
#[extract_component_filter(With<Camera>)]
#[reflect(Component, Default)]
pub struct FogSettings {
/// The color of the fog effect.
///
/// **Tip:** The alpha channel of the color can be used to “modulate” the fog effect without
/// changing the fog falloff mode or parameters.
pub color: Color,
/// Color used to modulate the influence of directional light colors on the
/// fog, where the view direction aligns with each directional light direction,
/// producing a “glow” or light dispersion effect. (e.g. around the sun)
///
/// Use [`Color::NONE`] to disable the effect.
pub directional_light_color: Color,
/// The exponent applied to the directional light alignment calculation.
/// A higher value means a more concentrated “glow”.
pub directional_light_exponent: f32,
/// Determines which falloff mode to use, and its parameters.
pub falloff: FogFalloff,
}
/// Allows switching between different fog falloff modes, and configuring their parameters.
///
/// ## Convenience Methods
///
/// When using non-linear fog modes it can be hard to determine the right parameter values
/// for a given scene.
///
/// For easier artistic control, instead of creating the enum variants directly, you can use the
/// visibility-based convenience methods:
///
/// - For `FogFalloff::Exponential`:
/// - [`FogFalloff::from_visibility()`]
/// - [`FogFalloff::from_visibility_contrast()`]
///
/// - For `FogFalloff::ExponentialSquared`:
/// - [`FogFalloff::from_visibility_squared()`]
/// - [`FogFalloff::from_visibility_contrast_squared()`]
///
/// - For `FogFalloff::Atmospheric`:
/// - [`FogFalloff::from_visibility_color()`]
/// - [`FogFalloff::from_visibility_colors()`]
/// - [`FogFalloff::from_visibility_contrast_color()`]
/// - [`FogFalloff::from_visibility_contrast_colors()`]
#[derive(Debug, Clone, Reflect)]
pub enum FogFalloff {
/// A linear fog falloff that grows in intensity between `start` and `end` distances.
///
/// This falloff mode is simpler to control than other modes, however it can produce results that look “artificial”, depending on the scene.
///
/// ## Formula
///
/// The fog intensity for a given point in the scene is determined by the following formula:
///
/// ```text
/// let fog_intensity = 1.0 - ((end - distance) / (end - start)).clamp(0.0, 1.0);
/// ```
///
/// <svg width="370" height="212" viewBox="0 0 370 212" fill="none">
/// <title>Plot showing how linear fog falloff behaves for start and end values of 0.8 and 2.2, respectively.</title>
/// <path d="M331 151H42V49" stroke="currentColor" stroke-width="2"/>
/// <text font-family="sans-serif" fill="currentColor" style="white-space: pre" font-family="Inter" font-size="12" letter-spacing="0em"><tspan x="136" y="173.864">1</tspan></text>
/// <text font-family="sans-serif" fill="currentColor" style="white-space: pre" font-family="Inter" font-size="12" letter-spacing="0em"><tspan x="30" y="53.8636">1</tspan></text>
/// <text font-family="sans-serif" fill="currentColor" style="white-space: pre" font-family="Inter" font-size="12" letter-spacing="0em"><tspan x="42" y="173.864">0</tspan></text>
/// <text font-family="sans-serif" fill="currentColor" style="white-space: pre" font-family="Inter" font-size="12" letter-spacing="0em"><tspan x="232" y="173.864">2</tspan></text>
/// <text font-family="sans-serif" fill="currentColor" style="white-space: pre" font-family="Inter" font-size="12" letter-spacing="0em"><tspan x="332" y="173.864">3</tspan></text>
/// <text font-family="sans-serif" fill="currentColor" style="white-space: pre" font-family="Inter" font-size="12" letter-spacing="0em"><tspan x="161" y="190.864">distance</tspan></text>
/// <text font-family="sans-serif" transform="translate(10 132) rotate(-90)" fill="currentColor" style="white-space: pre" font-family="Inter" font-size="12" letter-spacing="0em"><tspan x="0" y="11.8636">fog intensity</tspan></text>
/// <path d="M43 150H117.227L263 48H331" stroke="#FF00E5"/>
/// <path d="M118 151V49" stroke="#FF00E5" stroke-dasharray="1 4"/>
/// <path d="M263 151V49" stroke="#FF00E5" stroke-dasharray="1 4"/>
/// <text font-family="sans-serif" fill="#FF00E5" style="white-space: pre" font-family="Inter" font-size="10" letter-spacing="0em"><tspan x="121" y="58.6364">start</tspan></text>
/// <text font-family="sans-serif" fill="#FF00E5" style="white-space: pre" font-family="Inter" font-size="10" letter-spacing="0em"><tspan x="267" y="58.6364">end</tspan></text>
/// </svg>
Linear {
/// Distance from the camera where fog is completely transparent, in world units.
start: f32,
/// Distance from the camera where fog is completely opaque, in world units.
end: f32,
},
/// An exponential fog falloff with a given `density`.
///
/// Initially gains intensity quickly with distance, then more slowly. Typically produces more natural results than [`FogFalloff::Linear`],
/// but is a bit harder to control.
///
/// To move the fog “further away”, use lower density values. To move it “closer” use higher density values.
///
/// ## Tips
///
/// - Use the [`FogFalloff::from_visibility()`] convenience method to create an exponential falloff with the proper
/// density for a desired visibility distance in world units;
/// - It's not _unusual_ to have very large or very small values for the density, depending on the scene
/// scale. Typically, for scenes with objects in the scale of thousands of units, you might want density values
/// in the ballpark of `0.001`. Conversely, for really small scale scenes you might want really high values of
/// density;
/// - Combine the `density` parameter with the [`FogSettings`] `color`'s alpha channel for easier artistic control.
///
/// ## Formula
///
/// The fog intensity for a given point in the scene is determined by the following formula:
///
/// ```text
/// let fog_intensity = 1.0 - 1.0 / (distance * density).exp();
/// ```
///
/// <svg width="370" height="212" viewBox="0 0 370 212" fill="none">
/// <title>Plot showing how exponential fog falloff behaves for different density values</title>
/// <mask id="mask0_3_31" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="42" y="42" width="286" height="108">
/// <rect x="42" y="42" width="286" height="108" fill="#D9D9D9"/>
/// </mask>
/// <g mask="url(#mask0_3_31)">
/// <path d="M42 150C42 150 98.3894 53 254.825 53L662 53" stroke="#FF003D" stroke-width="1"/>
/// <path d="M42 150C42 150 139.499 53 409.981 53L1114 53" stroke="#001AFF" stroke-width="1"/>
/// <path d="M42 150C42 150 206.348 53 662.281 53L1849 53" stroke="#14FF00" stroke-width="1"/>
/// </g>
/// <path d="M331 151H42V49" stroke="currentColor" stroke-width="2"/>
/// <text font-family="sans-serif" fill="currentColor" style="white-space: pre" font-size="12" letter-spacing="0em"><tspan x="136" y="173.864">1</tspan></text>
/// <text font-family="sans-serif" fill="currentColor" style="white-space: pre" font-size="12" letter-spacing="0em"><tspan x="30" y="53.8636">1</tspan></text>
/// <text font-family="sans-serif" fill="currentColor" style="white-space: pre" font-size="12" letter-spacing="0em"><tspan x="42" y="173.864">0</tspan></text>
/// <text font-family="sans-serif" fill="currentColor" style="white-space: pre" font-size="12" letter-spacing="0em"><tspan x="232" y="173.864">2</tspan></text>
/// <text font-family="sans-serif" fill="currentColor" style="white-space: pre" font-size="12" letter-spacing="0em"><tspan x="332" y="173.864">3</tspan></text>
/// <text font-family="sans-serif" fill="#FF003D" style="white-space: pre" font-size="10" letter-spacing="0em"><tspan x="77" y="64.6364">density = 2</tspan></text>
/// <text font-family="sans-serif" fill="#001AFF" style="white-space: pre" font-size="10" letter-spacing="0em"><tspan x="236" y="76.6364">density = 1</tspan></text>
/// <text font-family="sans-serif" fill="#14FF00" style="white-space: pre" font-size="10" letter-spacing="0em"><tspan x="205" y="115.636">density = 0.5</tspan></text>
/// <text font-family="sans-serif" fill="currentColor" style="white-space: pre" font-size="12" letter-spacing="0em"><tspan x="161" y="190.864">distance</tspan></text>
/// <text font-family="sans-serif" transform="translate(10 132) rotate(-90)" fill="currentColor" style="white-space: pre" font-size="12" letter-spacing="0em"><tspan x="0" y="11.8636">fog intensity</tspan></text>
/// </svg>
Exponential {
/// Multiplier applied to the world distance (within the exponential fog falloff calculation).
density: f32,
},
/// A squared exponential fog falloff with a given `density`.
///
/// Similar to [`FogFalloff::Exponential`], but grows more slowly in intensity for closer distances
/// before “catching up”.
///
/// To move the fog “further away”, use lower density values. To move it “closer” use higher density values.
///
/// ## Tips
///
/// - Use the [`FogFalloff::from_visibility_squared()`] convenience method to create an exponential squared falloff
/// with the proper density for a desired visibility distance in world units;
/// - Combine the `density` parameter with the [`FogSettings`] `color`'s alpha channel for easier artistic control.
///
/// ## Formula
///
/// The fog intensity for a given point in the scene is determined by the following formula:
///
/// ```text
/// let fog_intensity = 1.0 - 1.0 / (distance * density).powi(2).exp();
/// ```
///
/// <svg width="370" height="212" viewBox="0 0 370 212" fill="none">
/// <title>Plot showing how exponential squared fog falloff behaves for different density values</title>
/// <mask id="mask0_1_3" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="42" y="42" width="286" height="108">
/// <rect x="42" y="42" width="286" height="108" fill="#D9D9D9"/>
/// </mask>
/// <g mask="url(#mask0_1_3)">
/// <path d="M42 150C75.4552 150 74.9241 53.1724 166.262 53.1724L404 53.1724" stroke="#FF003D" stroke-width="1"/>
/// <path d="M42 150C107.986 150 106.939 53.1724 287.091 53.1724L756 53.1724" stroke="#001AFF" stroke-width="1"/>
/// <path d="M42 150C166.394 150 164.42 53.1724 504.035 53.1724L1388 53.1724" stroke="#14FF00" stroke-width="1"/>
/// </g>
/// <path d="M331 151H42V49" stroke="currentColor" stroke-width="2"/>
/// <text font-family="sans-serif" fill="currentColor" style="white-space: pre" font-size="12" letter-spacing="0em"><tspan x="136" y="173.864">1</tspan></text>
/// <text font-family="sans-serif" fill="currentColor" style="white-space: pre" font-size="12" letter-spacing="0em"><tspan x="30" y="53.8636">1</tspan></text>
/// <text font-family="sans-serif" fill="currentColor" style="white-space: pre" font-size="12" letter-spacing="0em"><tspan x="42" y="173.864">0</tspan></text>
/// <text font-family="sans-serif" fill="currentColor" style="white-space: pre" font-size="12" letter-spacing="0em"><tspan x="232" y="173.864">2</tspan></text>
/// <text font-family="sans-serif" fill="currentColor" style="white-space: pre" font-size="12" letter-spacing="0em"><tspan x="332" y="173.864">3</tspan></text>
/// <text font-family="sans-serif" fill="#FF003D" style="white-space: pre" font-size="10" letter-spacing="0em"><tspan x="61" y="54.6364">density = 2</tspan></text>
/// <text font-family="sans-serif" fill="#001AFF" style="white-space: pre" font-size="10" letter-spacing="0em"><tspan x="168" y="84.6364">density = 1</tspan></text>
/// <text font-family="sans-serif" fill="#14FF00" style="white-space: pre" font-size="10" letter-spacing="0em"><tspan x="174" y="121.636">density = 0.5</tspan></text>
/// <text font-family="sans-serif" fill="currentColor" style="white-space: pre" font-size="12" letter-spacing="0em"><tspan x="161" y="190.864">distance</tspan></text>
/// <text font-family="sans-serif" transform="translate(10 132) rotate(-90)" fill="currentColor" style="white-space: pre" font-size="12" letter-spacing="0em"><tspan x="0" y="11.8636">fog intensity</tspan></text>
/// </svg>
ExponentialSquared {
/// Multiplier applied to the world distance (within the exponential squared fog falloff calculation).
density: f32,
},
/// A more general form of the [`FogFalloff::Exponential`] mode. The falloff formula is separated into
/// two terms, `extinction` and `inscattering`, for a somewhat simplified atmospheric scattering model.
/// Additionally, individual color channels can have their own density values, resulting in a total of
/// six different configuration parameters.
///
/// ## Tips
///
/// - Use the [`FogFalloff::from_visibility_colors()`] or [`FogFalloff::from_visibility_color()`] convenience methods
/// to create an atmospheric falloff with the proper densities for a desired visibility distance in world units and
/// extinction and inscattering colors;
/// - Combine the atmospheric fog parameters with the [`FogSettings`] `color`'s alpha channel for easier artistic control.
///
/// ## Formula
///
/// Unlike other modes, atmospheric falloff doesn't use a simple intensity-based blend of fog color with
/// object color. Instead, it calculates per-channel extinction and inscattering factors, which are
/// then used to calculate the final color.
///
/// ```text
/// let extinction_factor = 1.0 - 1.0 / (distance * extinction).exp();
/// let inscattering_factor = 1.0 - 1.0 / (distance * inscattering).exp();
/// let result = input_color * (1.0 - extinction_factor) + fog_color * inscattering_factor;
/// ```
///
/// ## Equivalence to [`FogFalloff::Exponential`]
///
/// For a density value of `D`, the following two falloff modes will produce identical visual results:
///
/// ```
/// # use bevy_pbr::prelude::*;
/// # use bevy_math::prelude::*;
/// # const D: f32 = 0.5;
/// #
/// let exponential = FogFalloff::Exponential {
/// density: D,
/// };
///
/// let atmospheric = FogFalloff::Atmospheric {
/// extinction: Vec3::new(D, D, D),
/// inscattering: Vec3::new(D, D, D),
/// };
/// ```
///
/// **Note:** While the results are identical, [`FogFalloff::Atmospheric`] is computationally more expensive.
Atmospheric {
/// Controls how much light is removed due to atmospheric “extinction”, i.e. loss of light due to
/// photons being absorbed by atmospheric particles.
///
/// Each component can be thought of as an independent per `R`/`G`/`B` channel `density` factor from
/// [`FogFalloff::Exponential`]: Multiplier applied to the world distance (within the fog
/// falloff calculation) for that specific channel.
///
/// **Note:**
/// This value is not a `Color`, since it affects the channels exponentially in a non-intuitive way.
/// For artistic control, use the [`FogFalloff::from_visibility_colors()`] convenience method.
extinction: Vec3,
/// Controls how much light is added due to light scattering from the sun through the atmosphere.
///
/// Each component can be thought of as an independent per `R`/`G`/`B` channel `density` factor from
/// [`FogFalloff::Exponential`]: A multiplier applied to the world distance (within the fog
/// falloff calculation) for that specific channel.
///
/// **Note:**
/// This value is not a `Color`, since it affects the channels exponentially in a non-intuitive way.
/// For artistic control, use the [`FogFalloff::from_visibility_colors()`] convenience method.
inscattering: Vec3,
},
}
impl FogFalloff {
/// Creates a [`FogFalloff::Exponential`] value from the given visibility distance in world units,
/// using the revised Koschmieder contrast threshold, [`FogFalloff::REVISED_KOSCHMIEDER_CONTRAST_THRESHOLD`].
pub fn from_visibility(visibility: f32) -> FogFalloff {
FogFalloff::from_visibility_contrast(
visibility,
FogFalloff::REVISED_KOSCHMIEDER_CONTRAST_THRESHOLD,
)
}
/// Creates a [`FogFalloff::Exponential`] value from the given visibility distance in world units,
/// and a given contrast threshold in the range of `0.0` to `1.0`.
pub fn from_visibility_contrast(visibility: f32, contrast_threshold: f32) -> FogFalloff {
FogFalloff::Exponential {
density: FogFalloff::koschmieder(visibility, contrast_threshold),
}
}
/// Creates a [`FogFalloff::ExponentialSquared`] value from the given visibility distance in world units,
/// using the revised Koschmieder contrast threshold, [`FogFalloff::REVISED_KOSCHMIEDER_CONTRAST_THRESHOLD`].
pub fn from_visibility_squared(visibility: f32) -> FogFalloff {
FogFalloff::from_visibility_contrast_squared(
visibility,
FogFalloff::REVISED_KOSCHMIEDER_CONTRAST_THRESHOLD,
)
}
/// Creates a [`FogFalloff::ExponentialSquared`] value from the given visibility distance in world units,
/// and a given contrast threshold in the range of `0.0` to `1.0`.
pub fn from_visibility_contrast_squared(
visibility: f32,
contrast_threshold: f32,
) -> FogFalloff {
FogFalloff::ExponentialSquared {
density: (FogFalloff::koschmieder(visibility, contrast_threshold) / visibility).sqrt(),
}
}
/// Creates a [`FogFalloff::Atmospheric`] value from the given visibility distance in world units,
/// and a shared color for both extinction and inscattering, using the revised Koschmieder contrast threshold,
/// [`FogFalloff::REVISED_KOSCHMIEDER_CONTRAST_THRESHOLD`].
pub fn from_visibility_color(
visibility: f32,
extinction_inscattering_color: Color,
) -> FogFalloff {
FogFalloff::from_visibility_contrast_colors(
visibility,
FogFalloff::REVISED_KOSCHMIEDER_CONTRAST_THRESHOLD,
extinction_inscattering_color,
extinction_inscattering_color,
)
}
/// Creates a [`FogFalloff::Atmospheric`] value from the given visibility distance in world units,
/// extinction and inscattering colors, using the revised Koschmieder contrast threshold,
/// [`FogFalloff::REVISED_KOSCHMIEDER_CONTRAST_THRESHOLD`].
///
/// ## Tips
/// - Alpha values of the provided colors can modulate the `extinction` and `inscattering` effects;
/// - Using an `extinction_color` of [`Color::WHITE`] or [`Color::NONE`] disables the extinction effect;
/// - Using an `inscattering_color` of [`Color::BLACK`] or [`Color::NONE`] disables the inscattering effect.
pub fn from_visibility_colors(
visibility: f32,
extinction_color: Color,
inscattering_color: Color,
) -> FogFalloff {
FogFalloff::from_visibility_contrast_colors(
visibility,
FogFalloff::REVISED_KOSCHMIEDER_CONTRAST_THRESHOLD,
extinction_color,
inscattering_color,
)
}
/// Creates a [`FogFalloff::Atmospheric`] value from the given visibility distance in world units,
/// a contrast threshold in the range of `0.0` to `1.0`, and a shared color for both extinction and inscattering.
pub fn from_visibility_contrast_color(
visibility: f32,
contrast_threshold: f32,
extinction_inscattering_color: Color,
) -> FogFalloff {
FogFalloff::from_visibility_contrast_colors(
visibility,
contrast_threshold,
extinction_inscattering_color,
extinction_inscattering_color,
)
}
/// Creates a [`FogFalloff::Atmospheric`] value from the given visibility distance in world units,
/// a contrast threshold in the range of `0.0` to `1.0`, extinction and inscattering colors.
///
/// ## Tips
/// - Alpha values of the provided colors can modulate the `extinction` and `inscattering` effects;
/// - Using an `extinction_color` of [`Color::WHITE`] or [`Color::NONE`] disables the extinction effect;
/// - Using an `inscattering_color` of [`Color::BLACK`] or [`Color::NONE`] disables the inscattering effect.
pub fn from_visibility_contrast_colors(
visibility: f32,
contrast_threshold: f32,
extinction_color: Color,
inscattering_color: Color,
) -> FogFalloff {
use std::f32::consts::E;
let [r_e, g_e, b_e, a_e] = extinction_color.as_linear_rgba_f32();
let [r_i, g_i, b_i, a_i] = inscattering_color.as_linear_rgba_f32();
FogFalloff::Atmospheric {
extinction: Vec3::new(
// Values are subtracted from 1.0 here to preserve the intuitive/artistic meaning of
// colors, since they're later subtracted. (e.g. by giving a blue extinction color, you
// get blue and _not_ yellow results)
(1.0 - r_e).powf(E),
(1.0 - g_e).powf(E),
(1.0 - b_e).powf(E),
) * FogFalloff::koschmieder(visibility, contrast_threshold)
* a_e.powf(E),
inscattering: Vec3::new(r_i.powf(E), g_i.powf(E), b_i.powf(E))
* FogFalloff::koschmieder(visibility, contrast_threshold)
* a_i.powf(E),
}
}
/// A 2% contrast threshold was originally proposed by Koschmieder, being the
/// minimum visual contrast at which a human observer could detect an object.
/// We use a revised 5% contrast threshold, deemed more realistic for typical human observers.
pub const REVISED_KOSCHMIEDER_CONTRAST_THRESHOLD: f32 = 0.05;
/// Calculates the extinction coefficient β, from V and Cₜ, where:
///
/// - Cₜ is the contrast threshold, in the range of `0.0` to `1.0`
/// - V is the visibility distance in which a perfectly black object is still identifiable
/// against the horizon sky within the contrast threshold
///
/// We start with Koschmieder's equation:
///
/// ```text
/// -ln(Cₜ)
/// V = ─────────
/// β
/// ```
///
/// Multiplying both sides by β/V, that gives us:
///
/// ```text
/// -ln(Cₜ)
/// β = ─────────
/// V
/// ```
///
/// See:
/// - <https://en.wikipedia.org/wiki/Visibility>
/// - <https://www.biral.com/wp-content/uploads/2015/02/Introduction_to_visibility-v2-2.pdf>
pub fn koschmieder(v: f32, c_t: f32) -> f32 {
-c_t.ln() / v
}
}
impl Default for FogSettings {
fn default() -> Self {
FogSettings {
color: Color::rgba(1.0, 1.0, 1.0, 1.0),
falloff: FogFalloff::Linear {
start: 0.0,
end: 100.0,
},
directional_light_color: Color::NONE,
directional_light_exponent: 8.0,
}
}
}