Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_post_process/src/bloom/upsampling_pipeline.rs
9395 views
1
use bevy_core_pipeline::FullscreenShader;
2
3
use super::{
4
downsampling_pipeline::BloomUniforms, Bloom, BloomCompositeMode, BLOOM_TEXTURE_FORMAT,
5
};
6
use bevy_asset::{load_embedded_asset, AssetServer, Handle};
7
use bevy_ecs::{
8
prelude::{Component, Entity},
9
resource::Resource,
10
system::{Commands, Query, Res, ResMut},
11
};
12
use bevy_render::{
13
render_resource::{
14
binding_types::{sampler, texture_2d, uniform_buffer},
15
*,
16
},
17
view::ViewTarget,
18
};
19
use bevy_shader::Shader;
20
use bevy_utils::default;
21
22
#[derive(Component)]
23
pub struct UpsamplingPipelineIds {
24
pub id_main: CachedRenderPipelineId,
25
pub id_final: CachedRenderPipelineId,
26
}
27
28
#[derive(Resource)]
29
pub struct BloomUpsamplingPipeline {
30
pub bind_group_layout: BindGroupLayoutDescriptor,
31
/// The asset handle for the fullscreen vertex shader.
32
pub fullscreen_shader: FullscreenShader,
33
/// The fragment shader asset handle.
34
pub fragment_shader: Handle<Shader>,
35
}
36
37
#[derive(PartialEq, Eq, Hash, Clone)]
38
pub struct BloomUpsamplingPipelineKeys {
39
composite_mode: BloomCompositeMode,
40
final_pipeline: bool,
41
}
42
43
pub fn init_bloom_upscaling_pipeline(
44
mut commands: Commands,
45
fullscreen_shader: Res<FullscreenShader>,
46
asset_server: Res<AssetServer>,
47
) {
48
let bind_group_layout = BindGroupLayoutDescriptor::new(
49
"bloom_upsampling_bind_group_layout",
50
&BindGroupLayoutEntries::sequential(
51
ShaderStages::FRAGMENT,
52
(
53
// Input texture
54
texture_2d(TextureSampleType::Float { filterable: true }),
55
// Sampler
56
sampler(SamplerBindingType::Filtering),
57
// BloomUniforms
58
uniform_buffer::<BloomUniforms>(true),
59
),
60
),
61
);
62
63
commands.insert_resource(BloomUpsamplingPipeline {
64
bind_group_layout,
65
fullscreen_shader: fullscreen_shader.clone(),
66
fragment_shader: load_embedded_asset!(asset_server.as_ref(), "bloom.wgsl"),
67
});
68
}
69
70
impl SpecializedRenderPipeline for BloomUpsamplingPipeline {
71
type Key = BloomUpsamplingPipelineKeys;
72
73
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
74
let texture_format = if key.final_pipeline {
75
ViewTarget::TEXTURE_FORMAT_HDR
76
} else {
77
BLOOM_TEXTURE_FORMAT
78
};
79
80
let color_blend = match key.composite_mode {
81
BloomCompositeMode::EnergyConserving => {
82
// At the time of developing this we decided to blend our
83
// blur pyramid levels using native WGPU render pass blend
84
// constants. They are set in the bloom node's run function.
85
// This seemed like a good approach at the time which allowed
86
// us to perform complex calculations for blend levels on the CPU,
87
// however, we missed the fact that this prevented us from using
88
// textures to customize bloom appearance on individual parts
89
// of the screen and create effects such as lens dirt or
90
// screen blur behind certain UI elements.
91
//
92
// TODO: Use alpha instead of blend constants and move
93
// compute_blend_factor to the shader. The shader
94
// will likely need to know current mip number or
95
// mip "angle" (original texture is 0deg, max mip is 90deg)
96
// so make sure you give it that as a uniform.
97
// That does have to be provided per each pass unlike other
98
// uniforms that are set once.
99
BlendComponent {
100
src_factor: BlendFactor::Constant,
101
dst_factor: BlendFactor::OneMinusConstant,
102
operation: BlendOperation::Add,
103
}
104
}
105
BloomCompositeMode::Additive => BlendComponent {
106
src_factor: BlendFactor::Constant,
107
dst_factor: BlendFactor::One,
108
operation: BlendOperation::Add,
109
},
110
};
111
112
RenderPipelineDescriptor {
113
label: Some("bloom_upsampling_pipeline".into()),
114
layout: vec![self.bind_group_layout.clone()],
115
vertex: self.fullscreen_shader.to_vertex_state(),
116
fragment: Some(FragmentState {
117
shader: self.fragment_shader.clone(),
118
entry_point: Some("upsample".into()),
119
targets: vec![Some(ColorTargetState {
120
format: texture_format,
121
blend: Some(BlendState {
122
color: color_blend,
123
alpha: BlendComponent {
124
src_factor: BlendFactor::Zero,
125
dst_factor: BlendFactor::One,
126
operation: BlendOperation::Add,
127
},
128
}),
129
write_mask: ColorWrites::ALL,
130
})],
131
..default()
132
}),
133
..default()
134
}
135
}
136
}
137
138
pub fn prepare_upsampling_pipeline(
139
mut commands: Commands,
140
pipeline_cache: Res<PipelineCache>,
141
mut pipelines: ResMut<SpecializedRenderPipelines<BloomUpsamplingPipeline>>,
142
pipeline: Res<BloomUpsamplingPipeline>,
143
views: Query<(Entity, &Bloom)>,
144
) {
145
for (entity, bloom) in &views {
146
let pipeline_id = pipelines.specialize(
147
&pipeline_cache,
148
&pipeline,
149
BloomUpsamplingPipelineKeys {
150
composite_mode: bloom.composite_mode,
151
final_pipeline: false,
152
},
153
);
154
155
let pipeline_final_id = pipelines.specialize(
156
&pipeline_cache,
157
&pipeline,
158
BloomUpsamplingPipelineKeys {
159
composite_mode: bloom.composite_mode,
160
final_pipeline: true,
161
},
162
);
163
164
commands.entity(entity).insert(UpsamplingPipelineIds {
165
id_main: pipeline_id,
166
id_final: pipeline_final_id,
167
});
168
}
169
}
170
171