Path: blob/main/crates/bevy_solari/src/pathtracer/node.rs
9353 views
use super::{prepare::PathtracerAccumulationTexture, Pathtracer};1use crate::scene::RaytracingSceneBindings;2use bevy_asset::{load_embedded_asset, AssetServer};3use bevy_ecs::{prelude::*, resource::Resource, system::Commands};4use bevy_render::{5camera::ExtractedCamera,6render_resource::{7binding_types::{texture_storage_2d, uniform_buffer},8BindGroupEntries, BindGroupLayoutDescriptor, BindGroupLayoutEntries,9CachedComputePipelineId, ComputePassDescriptor, ComputePipelineDescriptor,10ImageSubresourceRange, PipelineCache, ShaderStages, StorageTextureAccess, TextureFormat,11},12renderer::{RenderContext, RenderDevice, ViewQuery},13view::{ViewTarget, ViewUniform, ViewUniformOffset, ViewUniforms},14};15use bevy_utils::default;1617/// Resource holding the pathtracer pipeline configuration.18#[derive(Resource)]19pub struct PathtracerPipelines {20bind_group_layout: BindGroupLayoutDescriptor,21pipeline: CachedComputePipelineId,22}2324/// Initializes the pathtracer pipelines at render startup.25pub fn init_pathtracer_pipelines(26mut commands: Commands,27pipeline_cache: Res<PipelineCache>,28scene_bindings: Res<RaytracingSceneBindings>,29asset_server: Res<AssetServer>,30) {31let bind_group_layout = BindGroupLayoutDescriptor::new(32"pathtracer_bind_group_layout",33&BindGroupLayoutEntries::sequential(34ShaderStages::COMPUTE,35(36texture_storage_2d(TextureFormat::Rgba32Float, StorageTextureAccess::ReadWrite),37texture_storage_2d(38ViewTarget::TEXTURE_FORMAT_HDR,39StorageTextureAccess::WriteOnly,40),41uniform_buffer::<ViewUniform>(true),42),43),44);4546let pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {47label: Some("pathtracer_pipeline".into()),48layout: vec![49scene_bindings.bind_group_layout.clone(),50bind_group_layout.clone(),51],52shader: load_embedded_asset!(asset_server.as_ref(), "pathtracer.wgsl"),53..default()54});5556commands.insert_resource(PathtracerPipelines {57bind_group_layout,58pipeline,59});60}6162pub fn pathtracer(63view: ViewQuery<(64&Pathtracer,65&PathtracerAccumulationTexture,66&ExtractedCamera,67&ViewTarget,68&ViewUniformOffset,69)>,70pathtracer_pipelines: Option<Res<PathtracerPipelines>>,71pipeline_cache: Res<PipelineCache>,72scene_bindings: Res<RaytracingSceneBindings>,73view_uniforms: Res<ViewUniforms>,74render_device: Res<RenderDevice>,75mut ctx: RenderContext,76) {77let (pathtracer_settings, accumulation_texture, camera, view_target, view_uniform_offset) =78view.into_inner();7980let Some(pathtracer_pipelines) = pathtracer_pipelines else {81return;82};8384let (Some(pipeline), Some(scene_bind_group), Some(viewport), Some(view_uniforms_binding)) = (85pipeline_cache.get_compute_pipeline(pathtracer_pipelines.pipeline),86&scene_bindings.bind_group,87camera.physical_viewport_size,88view_uniforms.uniforms.binding(),89) else {90return;91};9293let bind_group = render_device.create_bind_group(94"pathtracer_bind_group",95&pipeline_cache.get_bind_group_layout(&pathtracer_pipelines.bind_group_layout),96&BindGroupEntries::sequential((97&accumulation_texture.0.default_view,98view_target.get_unsampled_color_attachment().view,99view_uniforms_binding,100)),101);102103let command_encoder = ctx.command_encoder();104105if pathtracer_settings.reset {106command_encoder.clear_texture(107&accumulation_texture.0.texture,108&ImageSubresourceRange::default(),109);110}111112let mut pass = command_encoder.begin_compute_pass(&ComputePassDescriptor {113label: Some("pathtracer"),114timestamp_writes: None,115});116pass.set_pipeline(pipeline);117pass.set_bind_group(0, scene_bind_group, &[]);118pass.set_bind_group(1, &bind_group, &[view_uniform_offset.offset]);119pass.dispatch_workgroups(viewport.x.div_ceil(8), viewport.y.div_ceil(8), 1);120}121122123