Path: blob/main/crates/bevy_pbr/src/volumetric_fog/mod.rs
6601 views
//! Volumetric fog and volumetric lighting, also known as light shafts or god1//! rays.2//!3//! This module implements a more physically-accurate, but slower, form of fog4//! than the [`crate::fog`] module does. Notably, this *volumetric fog* allows5//! for light beams from directional lights to shine through, creating what is6//! known as *light shafts* or *god rays*.7//!8//! To add volumetric fog to a scene, add [`bevy_light::VolumetricFog`] to the9//! camera, and add [`bevy_light::VolumetricLight`] to directional lights that you wish to10//! be volumetric. [`bevy_light::VolumetricFog`] feature numerous settings that11//! allow you to define the accuracy of the simulation, as well as the look of12//! the fog. Currently, only interaction with directional lights that have13//! shadow maps is supported. Note that the overhead of the effect scales14//! directly with the number of directional lights in use, so apply15//! [`bevy_light::VolumetricLight`] sparingly for the best results.16//!17//! The overall algorithm, which is implemented as a postprocessing effect, is a18//! combination of the techniques described in [Scratchapixel] and [this blog19//! post]. It uses raymarching in screen space, transformed into shadow map20//! space for sampling and combined with physically-based modeling of absorption21//! and scattering. Bevy employs the widely-used [Henyey-Greenstein phase22//! function] to model asymmetry; this essentially allows light shafts to fade23//! into and out of existence as the user views them.24//!25//! [Scratchapixel]: https://www.scratchapixel.com/lessons/3d-basic-rendering/volume-rendering-for-developers/intro-volume-rendering.html26//!27//! [this blog post]: https://www.alexandre-pestana.com/volumetric-lights/28//!29//! [Henyey-Greenstein phase function]: https://www.pbr-book.org/4ed/Volume_Scattering/Phase_Functions#TheHenyeyndashGreensteinPhaseFunction3031use bevy_app::{App, Plugin};32use bevy_asset::{embedded_asset, Assets, Handle};33use bevy_core_pipeline::core_3d::{34graph::{Core3d, Node3d},35prepare_core_3d_depth_textures,36};37use bevy_ecs::{resource::Resource, schedule::IntoScheduleConfigs as _};38use bevy_light::FogVolume;39use bevy_math::{40primitives::{Cuboid, Plane3d},41Vec2, Vec3,42};43use bevy_mesh::{Mesh, Meshable};44use bevy_render::{45render_graph::{RenderGraphExt, ViewNodeRunner},46render_resource::SpecializedRenderPipelines,47sync_component::SyncComponentPlugin,48ExtractSchedule, Render, RenderApp, RenderStartup, RenderSystems,49};50use render::{VolumetricFogNode, VolumetricFogPipeline, VolumetricFogUniformBuffer};5152use crate::{graph::NodePbr, volumetric_fog::render::init_volumetric_fog_pipeline};5354pub mod render;5556/// A plugin that implements volumetric fog.57pub struct VolumetricFogPlugin;5859#[derive(Resource)]60pub struct FogAssets {61plane_mesh: Handle<Mesh>,62cube_mesh: Handle<Mesh>,63}6465impl Plugin for VolumetricFogPlugin {66fn build(&self, app: &mut App) {67embedded_asset!(app, "volumetric_fog.wgsl");6869let mut meshes = app.world_mut().resource_mut::<Assets<Mesh>>();70let plane_mesh = meshes.add(Plane3d::new(Vec3::Z, Vec2::ONE).mesh());71let cube_mesh = meshes.add(Cuboid::new(1.0, 1.0, 1.0).mesh());7273app.add_plugins(SyncComponentPlugin::<FogVolume>::default());7475let Some(render_app) = app.get_sub_app_mut(RenderApp) else {76return;77};7879render_app80.insert_resource(FogAssets {81plane_mesh,82cube_mesh,83})84.init_resource::<SpecializedRenderPipelines<VolumetricFogPipeline>>()85.init_resource::<VolumetricFogUniformBuffer>()86.add_systems(RenderStartup, init_volumetric_fog_pipeline)87.add_systems(ExtractSchedule, render::extract_volumetric_fog)88.add_systems(89Render,90(91render::prepare_volumetric_fog_pipelines.in_set(RenderSystems::Prepare),92render::prepare_volumetric_fog_uniforms.in_set(RenderSystems::Prepare),93render::prepare_view_depth_textures_for_volumetric_fog94.in_set(RenderSystems::Prepare)95.before(prepare_core_3d_depth_textures),96),97)98.add_render_graph_node::<ViewNodeRunner<VolumetricFogNode>>(99Core3d,100NodePbr::VolumetricFog,101)102.add_render_graph_edges(103Core3d,104// Volumetric fog should run after the main pass but before bloom, so105// we order if at the start of post processing.106(107Node3d::EndMainPass,108NodePbr::VolumetricFog,109Node3d::StartMainPassPostProcessing,110),111);112}113}114115116