Path: blob/main/crates/bevy_post_process/src/bloom/downsampling_pipeline.rs
6596 views
use bevy_core_pipeline::FullscreenShader;12use super::{Bloom, BLOOM_TEXTURE_FORMAT};3use bevy_asset::{load_embedded_asset, AssetServer, Handle};4use bevy_ecs::{5prelude::{Component, Entity},6resource::Resource,7system::{Commands, Query, Res, ResMut},8};9use bevy_math::{Vec2, Vec4};10use bevy_render::{11render_resource::{12binding_types::{sampler, texture_2d, uniform_buffer},13*,14},15renderer::RenderDevice,16};17use bevy_shader::Shader;18use bevy_utils::default;1920#[derive(Component)]21pub struct BloomDownsamplingPipelineIds {22pub main: CachedRenderPipelineId,23pub first: CachedRenderPipelineId,24}2526#[derive(Resource)]27pub struct BloomDownsamplingPipeline {28/// Layout with a texture, a sampler, and uniforms29pub bind_group_layout: BindGroupLayout,30pub sampler: Sampler,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 BloomDownsamplingPipelineKeys {39prefilter: bool,40first_downsample: bool,41uniform_scale: bool,42}4344/// The uniform struct extracted from [`Bloom`] attached to a Camera.45/// Will be available for use in the Bloom shader.46#[derive(Component, ShaderType, Clone)]47pub struct BloomUniforms {48// Precomputed values used when thresholding, see https://catlikecoding.com/unity/tutorials/advanced-rendering/bloom/#3.449pub threshold_precomputations: Vec4,50pub viewport: Vec4,51pub scale: Vec2,52pub aspect: f32,53}5455pub fn init_bloom_downsampling_pipeline(56mut commands: Commands,57render_device: Res<RenderDevice>,58fullscreen_shader: Res<FullscreenShader>,59asset_server: Res<AssetServer>,60) {61// Bind group layout62let bind_group_layout = render_device.create_bind_group_layout(63"bloom_downsampling_bind_group_layout_with_settings",64&BindGroupLayoutEntries::sequential(65ShaderStages::FRAGMENT,66(67// Input texture binding68texture_2d(TextureSampleType::Float { filterable: true }),69// Sampler binding70sampler(SamplerBindingType::Filtering),71// Downsampling settings binding72uniform_buffer::<BloomUniforms>(true),73),74),75);7677// Sampler78let sampler = render_device.create_sampler(&SamplerDescriptor {79min_filter: FilterMode::Linear,80mag_filter: FilterMode::Linear,81address_mode_u: AddressMode::ClampToEdge,82address_mode_v: AddressMode::ClampToEdge,83..Default::default()84});8586commands.insert_resource(BloomDownsamplingPipeline {87bind_group_layout,88sampler,89fullscreen_shader: fullscreen_shader.clone(),90fragment_shader: load_embedded_asset!(asset_server.as_ref(), "bloom.wgsl"),91});92}9394impl SpecializedRenderPipeline for BloomDownsamplingPipeline {95type Key = BloomDownsamplingPipelineKeys;9697fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {98let layout = vec![self.bind_group_layout.clone()];99100let entry_point = if key.first_downsample {101"downsample_first".into()102} else {103"downsample".into()104};105106let mut shader_defs = vec![];107108if key.first_downsample {109shader_defs.push("FIRST_DOWNSAMPLE".into());110}111112if key.prefilter {113shader_defs.push("USE_THRESHOLD".into());114}115116if key.uniform_scale {117shader_defs.push("UNIFORM_SCALE".into());118}119120RenderPipelineDescriptor {121label: Some(122if key.first_downsample {123"bloom_downsampling_pipeline_first"124} else {125"bloom_downsampling_pipeline"126}127.into(),128),129layout,130vertex: self.fullscreen_shader.to_vertex_state(),131fragment: Some(FragmentState {132shader: self.fragment_shader.clone(),133shader_defs,134entry_point: Some(entry_point),135targets: vec![Some(ColorTargetState {136format: BLOOM_TEXTURE_FORMAT,137blend: None,138write_mask: ColorWrites::ALL,139})],140}),141..default()142}143}144}145146pub fn prepare_downsampling_pipeline(147mut commands: Commands,148pipeline_cache: Res<PipelineCache>,149mut pipelines: ResMut<SpecializedRenderPipelines<BloomDownsamplingPipeline>>,150pipeline: Res<BloomDownsamplingPipeline>,151views: Query<(Entity, &Bloom)>,152) {153for (entity, bloom) in &views {154let prefilter = bloom.prefilter.threshold > 0.0;155156let pipeline_id = pipelines.specialize(157&pipeline_cache,158&pipeline,159BloomDownsamplingPipelineKeys {160prefilter,161first_downsample: false,162uniform_scale: bloom.scale == Vec2::ONE,163},164);165166let pipeline_first_id = pipelines.specialize(167&pipeline_cache,168&pipeline,169BloomDownsamplingPipelineKeys {170prefilter,171first_downsample: true,172uniform_scale: bloom.scale == Vec2::ONE,173},174);175176commands177.entity(entity)178.insert(BloomDownsamplingPipelineIds {179first: pipeline_first_id,180main: pipeline_id,181});182}183}184185186