Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_post_process/src/bloom/downsampling_pipeline.rs
6596 views
1
use bevy_core_pipeline::FullscreenShader;
2
3
use super::{Bloom, BLOOM_TEXTURE_FORMAT};
4
use bevy_asset::{load_embedded_asset, AssetServer, Handle};
5
use bevy_ecs::{
6
prelude::{Component, Entity},
7
resource::Resource,
8
system::{Commands, Query, Res, ResMut},
9
};
10
use bevy_math::{Vec2, Vec4};
11
use bevy_render::{
12
render_resource::{
13
binding_types::{sampler, texture_2d, uniform_buffer},
14
*,
15
},
16
renderer::RenderDevice,
17
};
18
use bevy_shader::Shader;
19
use bevy_utils::default;
20
21
#[derive(Component)]
22
pub struct BloomDownsamplingPipelineIds {
23
pub main: CachedRenderPipelineId,
24
pub first: CachedRenderPipelineId,
25
}
26
27
#[derive(Resource)]
28
pub struct BloomDownsamplingPipeline {
29
/// Layout with a texture, a sampler, and uniforms
30
pub bind_group_layout: BindGroupLayout,
31
pub sampler: Sampler,
32
/// The asset handle for the fullscreen vertex shader.
33
pub fullscreen_shader: FullscreenShader,
34
/// The fragment shader asset handle.
35
pub fragment_shader: Handle<Shader>,
36
}
37
38
#[derive(PartialEq, Eq, Hash, Clone)]
39
pub struct BloomDownsamplingPipelineKeys {
40
prefilter: bool,
41
first_downsample: bool,
42
uniform_scale: bool,
43
}
44
45
/// The uniform struct extracted from [`Bloom`] attached to a Camera.
46
/// Will be available for use in the Bloom shader.
47
#[derive(Component, ShaderType, Clone)]
48
pub struct BloomUniforms {
49
// Precomputed values used when thresholding, see https://catlikecoding.com/unity/tutorials/advanced-rendering/bloom/#3.4
50
pub threshold_precomputations: Vec4,
51
pub viewport: Vec4,
52
pub scale: Vec2,
53
pub aspect: f32,
54
}
55
56
pub fn init_bloom_downsampling_pipeline(
57
mut commands: Commands,
58
render_device: Res<RenderDevice>,
59
fullscreen_shader: Res<FullscreenShader>,
60
asset_server: Res<AssetServer>,
61
) {
62
// Bind group layout
63
let bind_group_layout = render_device.create_bind_group_layout(
64
"bloom_downsampling_bind_group_layout_with_settings",
65
&BindGroupLayoutEntries::sequential(
66
ShaderStages::FRAGMENT,
67
(
68
// Input texture binding
69
texture_2d(TextureSampleType::Float { filterable: true }),
70
// Sampler binding
71
sampler(SamplerBindingType::Filtering),
72
// Downsampling settings binding
73
uniform_buffer::<BloomUniforms>(true),
74
),
75
),
76
);
77
78
// Sampler
79
let sampler = render_device.create_sampler(&SamplerDescriptor {
80
min_filter: FilterMode::Linear,
81
mag_filter: FilterMode::Linear,
82
address_mode_u: AddressMode::ClampToEdge,
83
address_mode_v: AddressMode::ClampToEdge,
84
..Default::default()
85
});
86
87
commands.insert_resource(BloomDownsamplingPipeline {
88
bind_group_layout,
89
sampler,
90
fullscreen_shader: fullscreen_shader.clone(),
91
fragment_shader: load_embedded_asset!(asset_server.as_ref(), "bloom.wgsl"),
92
});
93
}
94
95
impl SpecializedRenderPipeline for BloomDownsamplingPipeline {
96
type Key = BloomDownsamplingPipelineKeys;
97
98
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
99
let layout = vec![self.bind_group_layout.clone()];
100
101
let entry_point = if key.first_downsample {
102
"downsample_first".into()
103
} else {
104
"downsample".into()
105
};
106
107
let mut shader_defs = vec![];
108
109
if key.first_downsample {
110
shader_defs.push("FIRST_DOWNSAMPLE".into());
111
}
112
113
if key.prefilter {
114
shader_defs.push("USE_THRESHOLD".into());
115
}
116
117
if key.uniform_scale {
118
shader_defs.push("UNIFORM_SCALE".into());
119
}
120
121
RenderPipelineDescriptor {
122
label: Some(
123
if key.first_downsample {
124
"bloom_downsampling_pipeline_first"
125
} else {
126
"bloom_downsampling_pipeline"
127
}
128
.into(),
129
),
130
layout,
131
vertex: self.fullscreen_shader.to_vertex_state(),
132
fragment: Some(FragmentState {
133
shader: self.fragment_shader.clone(),
134
shader_defs,
135
entry_point: Some(entry_point),
136
targets: vec![Some(ColorTargetState {
137
format: BLOOM_TEXTURE_FORMAT,
138
blend: None,
139
write_mask: ColorWrites::ALL,
140
})],
141
}),
142
..default()
143
}
144
}
145
}
146
147
pub fn prepare_downsampling_pipeline(
148
mut commands: Commands,
149
pipeline_cache: Res<PipelineCache>,
150
mut pipelines: ResMut<SpecializedRenderPipelines<BloomDownsamplingPipeline>>,
151
pipeline: Res<BloomDownsamplingPipeline>,
152
views: Query<(Entity, &Bloom)>,
153
) {
154
for (entity, bloom) in &views {
155
let prefilter = bloom.prefilter.threshold > 0.0;
156
157
let pipeline_id = pipelines.specialize(
158
&pipeline_cache,
159
&pipeline,
160
BloomDownsamplingPipelineKeys {
161
prefilter,
162
first_downsample: false,
163
uniform_scale: bloom.scale == Vec2::ONE,
164
},
165
);
166
167
let pipeline_first_id = pipelines.specialize(
168
&pipeline_cache,
169
&pipeline,
170
BloomDownsamplingPipelineKeys {
171
prefilter,
172
first_downsample: true,
173
uniform_scale: bloom.scale == Vec2::ONE,
174
},
175
);
176
177
commands
178
.entity(entity)
179
.insert(BloomDownsamplingPipelineIds {
180
first: pipeline_first_id,
181
main: pipeline_id,
182
});
183
}
184
}
185
186