1#![expect(missing_docs, reason = "Not all docs are written yet, see #3492.")]
2#![forbid(unsafe_code)]
3#![cfg_attr(docsrs, feature(doc_cfg))]
4#![doc(
5 html_logo_url = "https://bevy.org/assets/icon.png",
6 html_favicon_url = "https://bevy.org/assets/icon.png"
7)]
89pub mod auto_exposure;
10pub mod bloom;
11pub mod dof;
12pub mod effect_stack;
13pub mod motion_blur;
14pub mod msaa_writeback;
1516use crate::{
17bloom::BloomPlugin, dof::DepthOfFieldPlugin, effect_stack::EffectStackPlugin,
18motion_blur::MotionBlurPlugin, msaa_writeback::MsaaWritebackPlugin,
19};
20use bevy_app::{App, Plugin};
21use bevy_shader::load_shader_library;
2223/// Adds bloom, motion blur, depth of field, and chromatic aberration support.
24#[derive(#[automatically_derived]
impl ::core::default::Default for PostProcessPlugin {
#[inline]
fn default() -> PostProcessPlugin { PostProcessPlugin {} }
}Default)]
25pub struct PostProcessPlugin;
2627impl Pluginfor PostProcessPlugin {
28fn build(&self, app: &mut App) {
29{
{
let mut embedded =
app.world_mut().resource_mut::<::bevy_asset::io::embedded::EmbeddedAssetRegistry>();
let path =
{
let crate_name =
"bevy_post_process".split(':').next().unwrap();
::bevy_asset::io::embedded::_embedded_asset_path(crate_name,
"src".as_ref(), "src/lib.rs".as_ref(),
"gaussian_blur.wgsl".as_ref())
};
let watched_path =
::bevy_asset::io::embedded::watched_path("src/lib.rs",
"gaussian_blur.wgsl");
embedded.insert_asset(watched_path, &path,
b"// A library containing a 1D Gaussian blur kernel.\n//\n// This is used by depth of field, but you can also use it in custom\n// postprocessing passes.\n\n#define_import_path bevy_post_process::gaussian_blur\n\n// Performs a single direction of the separable Gaussian blur kernel.\n//\n// * `color_texture` is the texture to blur.\n//\n// * `color_texture_sampler` is a sampler to sample the texture. It must have\n// linear filtering for both minification and magnification.\n//\n// * `frag_coord` is the screen-space pixel coordinate of the fragment (i.e. the\n// `position` input to the fragment).\n//\n// * `coc` is the diameter (not the radius) of the circle of confusion for this\n// fragment.\n//\n// * `frag_offset` is the vector, in screen-space units, from one sample to the\n// next. For a horizontal blur this will be `vec2(1.0, 0.0)`; for a vertical\n// blur this will be `vec2(0.0, 1.0)`.\n//\n// Returns the resulting color of the fragment.\nfn gaussian_blur(color_texture: texture_2d<f32>, color_texture_sampler: sampler, frag_coord: vec4<f32>, coc: f32, frag_offset: vec2<f32>) -> vec4<f32> {\n // Usually \xcf\x83 (the standard deviation) is half the radius, and the radius is\n // half the CoC. So we multiply by 0.25.\n let sigma = coc * 0.25;\n\n // 1.5\xcf\x83 is a good, somewhat aggressive default for support\xe2\x80\x94the number of\n // texels on each side of the center that we process.\n let support = i32(ceil(sigma * 1.5));\n let uv = frag_coord.xy / vec2<f32>(textureDimensions(color_texture));\n let offset = frag_offset / vec2<f32>(textureDimensions(color_texture));\n\n // The probability density function of the Gaussian blur is (up to constant factors) `exp(-1 / 2\xcf\x83\xc2\xb2 *\n // x\xc2\xb2). We precalculate the constant factor here to avoid having to\n // calculate it in the inner loop.\n let exp_factor = -1.0 / (2.0 * sigma * sigma);\n\n // Accumulate samples on both sides of the current texel. Go two at a time,\n // taking advantage of bilinear filtering.\n var sum = textureSampleLevel(color_texture, color_texture_sampler, uv, 0.0).rgb;\n var weight_sum = 1.0;\n for (var i = 1; i <= support; i += 2) {\n // This is a well-known trick to reduce the number of needed texture\n // samples by a factor of two. We seek to accumulate two adjacent\n // samples c\xe2\x82\x80 and c\xe2\x82\x81 with weights w\xe2\x82\x80 and w\xe2\x82\x81 respectively, with a single\n // texture sample at a carefully chosen location. Observe that:\n //\n // k \xe2\x8b\x85 lerp(c\xe2\x82\x80, c\xe2\x82\x81, t) = w\xe2\x82\x80\xe2\x8b\x85c\xe2\x82\x80 + w\xe2\x82\x81\xe2\x8b\x85c\xe2\x82\x81\n //\n // w\xe2\x82\x81\n // if k = w\xe2\x82\x80 + w\xe2\x82\x81 and t = \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\n // w\xe2\x82\x80 + w\xe2\x82\x81\n //\n // Therefore, if we sample at a distance of t = w\xe2\x82\x81 / (w\xe2\x82\x80 + w\xe2\x82\x81) texels in\n // between the two texel centers and scale by k = w\xe2\x82\x80 + w\xe2\x82\x81 afterward, we\n // effectively evaluate w\xe2\x82\x80\xe2\x8b\x85c\xe2\x82\x80 + w\xe2\x82\x81\xe2\x8b\x85c\xe2\x82\x81 with a single texture lookup.\n let w0 = exp(exp_factor * f32(i) * f32(i));\n let w1 = exp(exp_factor * f32(i + 1) * f32(i + 1));\n let uv_offset = offset * (f32(i) + w1 / (w0 + w1));\n let weight = w0 + w1;\n\n sum += (\n textureSampleLevel(color_texture, color_texture_sampler, uv + uv_offset, 0.0).rgb +\n textureSampleLevel(color_texture, color_texture_sampler, uv - uv_offset, 0.0).rgb\n ) * weight;\n weight_sum += weight * 2.0;\n }\n\n return vec4(sum / weight_sum, 1.0);\n}\n\n");
}
};
let handle:
::bevy_shader::_macro::bevy_asset::prelude::Handle<::bevy_shader::prelude::Shader> =
{
let (path, asset_server) =
{
let path =
{
{
let crate_name =
"bevy_post_process".split(':').next().unwrap();
::bevy_asset::io::embedded::_embedded_asset_path(crate_name,
"src".as_ref(), "src/lib.rs".as_ref(),
"gaussian_blur.wgsl".as_ref())
}
};
let path =
::bevy_asset::AssetPath::from_path_buf(path).with_source("embedded");
let asset_server =
::bevy_asset::io::embedded::GetAssetServer::get_asset_server(app);
(path, asset_server)
};
asset_server.load(path)
};
core::mem::forget(handle);load_shader_library!(app, "gaussian_blur.wgsl");
3031app.add_plugins((
32MsaaWritebackPlugin,
33BloomPlugin,
34MotionBlurPlugin,
35DepthOfFieldPlugin,
36EffectStackPlugin,
37 ));
38 }
39}