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