mirror of
https://github.com/bevyengine/bevy
synced 2024-11-26 06:30:19 +00:00
51c70bc98c
# Objective Fog color was passed to shaders without conversion from sRGB to linear color space. Because shaders expect colors in linear space this resulted in wrong color being used. This is most noticeable in open scenes with dark fog color and clear color set to the same color. In such case background/clear color (which is properly processed) is going to be darker than very far objects. Example: ![image](https://github.com/bevyengine/bevy/assets/160391/89b70d97-b2d0-4bc5-80f4-c9e8b8801c4c) [bevy-fog-color-bug.zip](https://github.com/bevyengine/bevy/files/13063718/bevy-fog-color-bug.zip) ## Solution Add missing conversion of fog color to linear color space. --- ## Changelog * Fixed conversion of fog color ## Migration Guide - Colors in `FogSettings` struct (`color` and `directional_light_color`) are now sent to the GPU in linear space. If you were using `Color::rgb()`/`Color::rgba()` and would like to retain the previous colors, you can quickly fix it by switching to `Color::rgb_linear()`/`Color::rgba_linear()`.
316 lines
9 KiB
Rust
316 lines
9 KiB
Rust
//! This interactive example shows how to use distance fog,
|
|
//! and allows playing around with different fog settings.
|
|
//!
|
|
//! ## Controls
|
|
//!
|
|
//! | Key Binding | Action |
|
|
//! |:-------------------|:------------------------------------|
|
|
//! | `1` / `2` / `3` | Fog Falloff Mode |
|
|
//! | `A` / `S` | Move Start Distance (Linear Fog) |
|
|
//! | | Change Density (Exponential Fogs) |
|
|
//! | `Z` / `X` | Move End Distance (Linear Fog) |
|
|
//! | `-` / `=` | Adjust Fog Red Channel |
|
|
//! | `[` / `]` | Adjust Fog Green Channel |
|
|
//! | `;` / `'` | Adjust Fog Blue Channel |
|
|
//! | `.` / `?` | Adjust Fog Alpha Channel |
|
|
|
|
use bevy::{
|
|
pbr::{NotShadowCaster, NotShadowReceiver},
|
|
prelude::*,
|
|
};
|
|
|
|
fn main() {
|
|
App::new()
|
|
.add_plugins(DefaultPlugins)
|
|
.add_systems(
|
|
Startup,
|
|
(setup_camera_fog, setup_pyramid_scene, setup_instructions),
|
|
)
|
|
.add_systems(Update, update_system)
|
|
.run();
|
|
}
|
|
|
|
fn setup_camera_fog(mut commands: Commands) {
|
|
commands.spawn((
|
|
Camera3dBundle::default(),
|
|
FogSettings {
|
|
color: Color::rgba(0.25, 0.25, 0.25, 1.0),
|
|
falloff: FogFalloff::Linear {
|
|
start: 5.0,
|
|
end: 20.0,
|
|
},
|
|
..default()
|
|
},
|
|
));
|
|
}
|
|
|
|
fn setup_pyramid_scene(
|
|
mut commands: Commands,
|
|
mut meshes: ResMut<Assets<Mesh>>,
|
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
|
) {
|
|
let stone = materials.add(StandardMaterial {
|
|
base_color: Color::hex("28221B").unwrap(),
|
|
perceptual_roughness: 1.0,
|
|
..default()
|
|
});
|
|
|
|
// pillars
|
|
for (x, z) in &[(-1.5, -1.5), (1.5, -1.5), (1.5, 1.5), (-1.5, 1.5)] {
|
|
commands.spawn(PbrBundle {
|
|
mesh: meshes.add(Mesh::from(shape::Box {
|
|
min_x: -0.5,
|
|
max_x: 0.5,
|
|
min_z: -0.5,
|
|
max_z: 0.5,
|
|
min_y: 0.0,
|
|
max_y: 3.0,
|
|
})),
|
|
material: stone.clone(),
|
|
transform: Transform::from_xyz(*x, 0.0, *z),
|
|
..default()
|
|
});
|
|
}
|
|
|
|
// orb
|
|
commands.spawn((
|
|
PbrBundle {
|
|
mesh: meshes.add(Mesh::try_from(shape::Icosphere::default()).unwrap()),
|
|
material: materials.add(StandardMaterial {
|
|
base_color: Color::hex("126212CC").unwrap(),
|
|
reflectance: 1.0,
|
|
perceptual_roughness: 0.0,
|
|
metallic: 0.5,
|
|
alpha_mode: AlphaMode::Blend,
|
|
..default()
|
|
}),
|
|
transform: Transform::from_scale(Vec3::splat(1.75))
|
|
.with_translation(Vec3::new(0.0, 4.0, 0.0)),
|
|
..default()
|
|
},
|
|
NotShadowCaster,
|
|
NotShadowReceiver,
|
|
));
|
|
|
|
// steps
|
|
for i in 0..50 {
|
|
let size = i as f32 / 2.0 + 3.0;
|
|
let y = -i as f32 / 2.0;
|
|
commands.spawn(PbrBundle {
|
|
mesh: meshes.add(Mesh::from(shape::Box {
|
|
min_x: -size,
|
|
max_x: size,
|
|
min_z: -size,
|
|
max_z: size,
|
|
min_y: 0.0,
|
|
max_y: 0.5,
|
|
})),
|
|
material: stone.clone(),
|
|
transform: Transform::from_xyz(0.0, y, 0.0),
|
|
..default()
|
|
});
|
|
}
|
|
|
|
// sky
|
|
commands.spawn(PbrBundle {
|
|
mesh: meshes.add(Mesh::from(shape::Box::default())),
|
|
material: materials.add(StandardMaterial {
|
|
base_color: Color::hex("888888").unwrap(),
|
|
unlit: true,
|
|
cull_mode: None,
|
|
..default()
|
|
}),
|
|
transform: Transform::from_scale(Vec3::splat(1_000_000.0)),
|
|
..default()
|
|
});
|
|
|
|
// light
|
|
commands.spawn(PointLightBundle {
|
|
transform: Transform::from_xyz(0.0, 1.0, 0.0),
|
|
point_light: PointLight {
|
|
intensity: 1500.,
|
|
range: 100.,
|
|
shadows_enabled: true,
|
|
..default()
|
|
},
|
|
..default()
|
|
});
|
|
}
|
|
|
|
fn setup_instructions(mut commands: Commands) {
|
|
commands.spawn(
|
|
TextBundle::from_section(
|
|
"",
|
|
TextStyle {
|
|
font_size: 20.0,
|
|
..default()
|
|
},
|
|
)
|
|
.with_style(Style {
|
|
position_type: PositionType::Absolute,
|
|
top: Val::Px(12.0),
|
|
left: Val::Px(12.0),
|
|
..default()
|
|
}),
|
|
);
|
|
}
|
|
|
|
fn update_system(
|
|
mut camera: Query<(&mut FogSettings, &mut Transform)>,
|
|
mut text: Query<&mut Text>,
|
|
time: Res<Time>,
|
|
keycode: Res<Input<KeyCode>>,
|
|
) {
|
|
let now = time.elapsed_seconds();
|
|
let delta = time.delta_seconds();
|
|
|
|
let (mut fog, mut transform) = camera.single_mut();
|
|
let mut text = text.single_mut();
|
|
|
|
// Orbit camera around pyramid
|
|
let orbit_scale = 8.0 + (now / 10.0).sin() * 7.0;
|
|
*transform = Transform::from_xyz(
|
|
(now / 5.0).cos() * orbit_scale,
|
|
12.0 - orbit_scale / 2.0,
|
|
(now / 5.0).sin() * orbit_scale,
|
|
)
|
|
.looking_at(Vec3::ZERO, Vec3::Y);
|
|
|
|
// Fog Information
|
|
text.sections[0].value = format!("Fog Falloff: {:?}\nFog Color: {:?}", fog.falloff, fog.color);
|
|
|
|
// Fog Falloff Mode Switching
|
|
text.sections[0]
|
|
.value
|
|
.push_str("\n\n1 / 2 / 3 - Fog Falloff Mode");
|
|
|
|
if keycode.pressed(KeyCode::Key1) {
|
|
if let FogFalloff::Linear { .. } = fog.falloff {
|
|
// No change
|
|
} else {
|
|
fog.falloff = FogFalloff::Linear {
|
|
start: 5.0,
|
|
end: 20.0,
|
|
};
|
|
};
|
|
}
|
|
|
|
if keycode.pressed(KeyCode::Key2) {
|
|
if let FogFalloff::Exponential { .. } = fog.falloff {
|
|
// No change
|
|
} else if let FogFalloff::ExponentialSquared { density } = fog.falloff {
|
|
fog.falloff = FogFalloff::Exponential { density };
|
|
} else {
|
|
fog.falloff = FogFalloff::Exponential { density: 0.07 };
|
|
};
|
|
}
|
|
|
|
if keycode.pressed(KeyCode::Key3) {
|
|
if let FogFalloff::Exponential { density } = fog.falloff {
|
|
fog.falloff = FogFalloff::ExponentialSquared { density };
|
|
} else if let FogFalloff::ExponentialSquared { .. } = fog.falloff {
|
|
// No change
|
|
} else {
|
|
fog.falloff = FogFalloff::Exponential { density: 0.07 };
|
|
};
|
|
}
|
|
|
|
// Linear Fog Controls
|
|
if let FogFalloff::Linear {
|
|
ref mut start,
|
|
ref mut end,
|
|
} = &mut fog.falloff
|
|
{
|
|
text.sections[0]
|
|
.value
|
|
.push_str("\nA / S - Move Start Distance\nZ / X - Move End Distance");
|
|
|
|
if keycode.pressed(KeyCode::A) {
|
|
*start -= delta * 3.0;
|
|
}
|
|
if keycode.pressed(KeyCode::S) {
|
|
*start += delta * 3.0;
|
|
}
|
|
if keycode.pressed(KeyCode::Z) {
|
|
*end -= delta * 3.0;
|
|
}
|
|
if keycode.pressed(KeyCode::X) {
|
|
*end += delta * 3.0;
|
|
}
|
|
}
|
|
|
|
// Exponential Fog Controls
|
|
if let FogFalloff::Exponential { ref mut density } = &mut fog.falloff {
|
|
text.sections[0].value.push_str("\nA / S - Change Density");
|
|
|
|
if keycode.pressed(KeyCode::A) {
|
|
*density -= delta * 0.5 * *density;
|
|
if *density < 0.0 {
|
|
*density = 0.0;
|
|
}
|
|
}
|
|
if keycode.pressed(KeyCode::S) {
|
|
*density += delta * 0.5 * *density;
|
|
}
|
|
}
|
|
|
|
// ExponentialSquared Fog Controls
|
|
if let FogFalloff::ExponentialSquared { ref mut density } = &mut fog.falloff {
|
|
text.sections[0].value.push_str("\nA / S - Change Density");
|
|
|
|
if keycode.pressed(KeyCode::A) {
|
|
*density -= delta * 0.5 * *density;
|
|
if *density < 0.0 {
|
|
*density = 0.0;
|
|
}
|
|
}
|
|
if keycode.pressed(KeyCode::S) {
|
|
*density += delta * 0.5 * *density;
|
|
}
|
|
}
|
|
|
|
// RGBA Controls
|
|
text.sections[0]
|
|
.value
|
|
.push_str("\n\n- / = - Red\n[ / ] - Green\n; / ' - Blue\n. / ? - Alpha");
|
|
|
|
if keycode.pressed(KeyCode::Minus) {
|
|
let r = (fog.color.r() - 0.1 * delta).max(0.0);
|
|
fog.color.set_r(r);
|
|
}
|
|
|
|
if keycode.pressed(KeyCode::Equals) {
|
|
let r = (fog.color.r() + 0.1 * delta).min(1.0);
|
|
fog.color.set_r(r);
|
|
}
|
|
|
|
if keycode.pressed(KeyCode::BracketLeft) {
|
|
let g = (fog.color.g() - 0.1 * delta).max(0.0);
|
|
fog.color.set_g(g);
|
|
}
|
|
|
|
if keycode.pressed(KeyCode::BracketRight) {
|
|
let g = (fog.color.g() + 0.1 * delta).min(1.0);
|
|
fog.color.set_g(g);
|
|
}
|
|
|
|
if keycode.pressed(KeyCode::Semicolon) {
|
|
let b = (fog.color.b() - 0.1 * delta).max(0.0);
|
|
fog.color.set_b(b);
|
|
}
|
|
|
|
if keycode.pressed(KeyCode::Apostrophe) {
|
|
let b = (fog.color.b() + 0.1 * delta).min(1.0);
|
|
fog.color.set_b(b);
|
|
}
|
|
|
|
if keycode.pressed(KeyCode::Period) {
|
|
let a = (fog.color.a() - 0.1 * delta).max(0.0);
|
|
fog.color.set_a(a);
|
|
}
|
|
|
|
if keycode.pressed(KeyCode::Slash) {
|
|
let a = (fog.color.a() + 0.1 * delta).min(1.0);
|
|
fog.color.set_a(a);
|
|
}
|
|
}
|