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