Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_pbr/src/render/fog.rs
6600 views
1
use bevy_app::{App, Plugin};
2
use bevy_color::{ColorToComponents, LinearRgba};
3
use bevy_ecs::prelude::*;
4
use bevy_math::{Vec3, Vec4};
5
use bevy_render::{
6
extract_component::ExtractComponentPlugin,
7
render_resource::{DynamicUniformBuffer, ShaderType},
8
renderer::{RenderDevice, RenderQueue},
9
view::ExtractedView,
10
Render, RenderApp, RenderSystems,
11
};
12
use bevy_shader::load_shader_library;
13
14
use crate::{DistanceFog, FogFalloff};
15
16
/// The GPU-side representation of the fog configuration that's sent as a uniform to the shader
17
#[derive(Copy, Clone, ShaderType, Default, Debug)]
18
pub struct GpuFog {
19
/// Fog color
20
base_color: Vec4,
21
/// The color used for the fog where the view direction aligns with directional lights
22
directional_light_color: Vec4,
23
/// Allocated differently depending on fog mode.
24
/// See `mesh_view_types.wgsl` for a detailed explanation
25
be: Vec3,
26
/// The exponent applied to the directional light alignment calculation
27
directional_light_exponent: f32,
28
/// Allocated differently depending on fog mode.
29
/// See `mesh_view_types.wgsl` for a detailed explanation
30
bi: Vec3,
31
/// Unsigned int representation of the active fog falloff mode
32
mode: u32,
33
}
34
35
// Important: These must be kept in sync with `mesh_view_types.wgsl`
36
const GPU_FOG_MODE_OFF: u32 = 0;
37
const GPU_FOG_MODE_LINEAR: u32 = 1;
38
const GPU_FOG_MODE_EXPONENTIAL: u32 = 2;
39
const GPU_FOG_MODE_EXPONENTIAL_SQUARED: u32 = 3;
40
const GPU_FOG_MODE_ATMOSPHERIC: u32 = 4;
41
42
/// Metadata for fog
43
#[derive(Default, Resource)]
44
pub struct FogMeta {
45
pub gpu_fogs: DynamicUniformBuffer<GpuFog>,
46
}
47
48
/// Prepares fog metadata and writes the fog-related uniform buffers to the GPU
49
pub fn prepare_fog(
50
mut commands: Commands,
51
render_device: Res<RenderDevice>,
52
render_queue: Res<RenderQueue>,
53
mut fog_meta: ResMut<FogMeta>,
54
views: Query<(Entity, Option<&DistanceFog>), With<ExtractedView>>,
55
) {
56
let views_iter = views.iter();
57
let view_count = views_iter.len();
58
let Some(mut writer) = fog_meta
59
.gpu_fogs
60
.get_writer(view_count, &render_device, &render_queue)
61
else {
62
return;
63
};
64
for (entity, fog) in views_iter {
65
let gpu_fog = if let Some(fog) = fog {
66
match &fog.falloff {
67
FogFalloff::Linear { start, end } => GpuFog {
68
mode: GPU_FOG_MODE_LINEAR,
69
base_color: LinearRgba::from(fog.color).to_vec4(),
70
directional_light_color: LinearRgba::from(fog.directional_light_color)
71
.to_vec4(),
72
directional_light_exponent: fog.directional_light_exponent,
73
be: Vec3::new(*start, *end, 0.0),
74
..Default::default()
75
},
76
FogFalloff::Exponential { density } => GpuFog {
77
mode: GPU_FOG_MODE_EXPONENTIAL,
78
base_color: LinearRgba::from(fog.color).to_vec4(),
79
directional_light_color: LinearRgba::from(fog.directional_light_color)
80
.to_vec4(),
81
directional_light_exponent: fog.directional_light_exponent,
82
be: Vec3::new(*density, 0.0, 0.0),
83
..Default::default()
84
},
85
FogFalloff::ExponentialSquared { density } => GpuFog {
86
mode: GPU_FOG_MODE_EXPONENTIAL_SQUARED,
87
base_color: LinearRgba::from(fog.color).to_vec4(),
88
directional_light_color: LinearRgba::from(fog.directional_light_color)
89
.to_vec4(),
90
directional_light_exponent: fog.directional_light_exponent,
91
be: Vec3::new(*density, 0.0, 0.0),
92
..Default::default()
93
},
94
FogFalloff::Atmospheric {
95
extinction,
96
inscattering,
97
} => GpuFog {
98
mode: GPU_FOG_MODE_ATMOSPHERIC,
99
base_color: LinearRgba::from(fog.color).to_vec4(),
100
directional_light_color: LinearRgba::from(fog.directional_light_color)
101
.to_vec4(),
102
directional_light_exponent: fog.directional_light_exponent,
103
be: *extinction,
104
bi: *inscattering,
105
},
106
}
107
} else {
108
// If no fog is added to a camera, by default it's off
109
GpuFog {
110
mode: GPU_FOG_MODE_OFF,
111
..Default::default()
112
}
113
};
114
115
// This is later read by `SetMeshViewBindGroup<I>`
116
commands.entity(entity).insert(ViewFogUniformOffset {
117
offset: writer.write(&gpu_fog),
118
});
119
}
120
}
121
122
/// Inserted on each `Entity` with an `ExtractedView` to keep track of its offset
123
/// in the `gpu_fogs` `DynamicUniformBuffer` within `FogMeta`
124
#[derive(Component)]
125
pub struct ViewFogUniformOffset {
126
pub offset: u32,
127
}
128
129
/// A plugin that consolidates fog extraction, preparation and related resources/assets
130
pub struct FogPlugin;
131
132
impl Plugin for FogPlugin {
133
fn build(&self, app: &mut App) {
134
load_shader_library!(app, "fog.wgsl");
135
136
app.add_plugins(ExtractComponentPlugin::<DistanceFog>::default());
137
138
if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
139
render_app
140
.init_resource::<FogMeta>()
141
.add_systems(Render, prepare_fog.in_set(RenderSystems::PrepareResources));
142
}
143
}
144
}
145
146