diff --git a/assets/sky-test.png b/assets/sky-test.png new file mode 100644 index 0000000..9a176f9 Binary files /dev/null and b/assets/sky-test.png differ diff --git a/assets/trace.wgsl b/assets/trace.wgsl index 92e4834..e97afc1 100644 --- a/assets/trace.wgsl +++ b/assets/trace.wgsl @@ -4,7 +4,8 @@ @group(0) @binding(1) var output: texture_storage_2d; @group(0) @binding(2) var config: TracerUniforms; - +@group(0) @binding(3) var skybox_texture: texture_cube; +@group(0) @binding(4) var skybox_sampler: sampler; struct View { view_proj: mat4x4, diff --git a/src/app.rs b/src/app.rs index 7eb749e..4a73909 100644 --- a/src/app.rs +++ b/src/app.rs @@ -36,7 +36,12 @@ impl Plugin for Blackhole { } } -fn setup(mut commands: Commands, mut images: ResMut>, window: Single<&Window, With>) { +fn setup( + mut commands: Commands, + mut images: ResMut>, + window: Single<&Window, With>, + asset_server: Res, +) { commands.spawn(( PerfUiRoot::default(), PerfUiEntryFPS::default(), @@ -70,6 +75,7 @@ fn setup(mut commands: Commands, mut images: ResMut>, window: Sing let img0 = images.add(image.clone()); let img1 = images.add(image); + let skybox = asset_server.load("sky-test.png"); commands.spawn(( Name::new("Render Sprite"), Sprite { @@ -97,5 +103,9 @@ fn setup(mut commands: Commands, mut images: ResMut>, window: Sing )) .insert(Camera { order: -1, ..default() }); - commands.insert_resource(TracerRenderTextures(img0, img1)); + commands.insert_resource(TracerRenderTextures { + main: img0, + secondary: img1, + skybox, + }); } diff --git a/src/components/rt.rs b/src/components/rt.rs index fed00f5..f6474ff 100644 --- a/src/components/rt.rs +++ b/src/components/rt.rs @@ -1,4 +1,4 @@ -use bevy::{prelude::*, render::render_resource::encase::private::ShaderType}; +use bevy::prelude::*; #[derive(Component)] pub struct RTCamera; diff --git a/src/render/node.rs b/src/render/node.rs index 1a16d3e..0e781ac 100644 --- a/src/render/node.rs +++ b/src/render/node.rs @@ -7,7 +7,7 @@ use bevy::{ }, }; -use crate::render::pipeline::{TracerImageBindGroups, TracerPipeline}; +use crate::render::pipeline::{TracerImageBindGroups, TracerPipeline, TracerRenderTextures}; use crate::{SHADER_ASSET_PATH, WORKGROUP_SIZE}; pub enum TracerState { @@ -36,16 +36,21 @@ impl render_graph::Node for TracerNode { // if the corresponding pipeline has loaded, transition to the next stage match self.state { TracerState::Loading => { - match pipeline_cache.get_compute_pipeline_state(pipeline.init_pipeline) { - CachedPipelineState::Ok(_) => { - self.state = TracerState::Init; - } + let shader_loaded = match pipeline_cache.get_compute_pipeline_state(pipeline.init_pipeline) { + CachedPipelineState::Ok(_) => true, // If the shader hasn't loaded yet, just wait. - CachedPipelineState::Err(PipelineCacheError::ShaderNotLoaded(_)) => {} + CachedPipelineState::Err(PipelineCacheError::ShaderNotLoaded(_)) => false, CachedPipelineState::Err(err) => { panic!("Initializing assets/{SHADER_ASSET_PATH}:\n{err}") } - _ => {} + _ => false, + }; + + let tex = world.resource::(); + let asset_server = world.resource::(); + let load_state = asset_server.get_load_state(tex.skybox.id()).unwrap(); + if load_state.is_loaded() && shader_loaded { + self.state = TracerState::Init; } } TracerState::Init => { diff --git a/src/render/pipeline.rs b/src/render/pipeline.rs index 1ccaf30..9f49e96 100644 --- a/src/render/pipeline.rs +++ b/src/render/pipeline.rs @@ -4,15 +4,14 @@ use bevy::{ prelude::*, render::{ Render, RenderApp, RenderSet, - camera::CameraProjection, extract_resource::{ExtractResource, ExtractResourcePlugin}, render_asset::RenderAssets, render_graph::{RenderGraph, RenderLabel}, render_resource::{ BindGroup, BindGroupEntries, BindGroupLayout, BindGroupLayoutEntries, CachedComputePipelineId, - ComputePipelineDescriptor, PipelineCache, ShaderStages, ShaderType, StorageTextureAccess, TextureFormat, - UniformBuffer, - binding_types::{texture_storage_2d, uniform_buffer}, + ComputePipelineDescriptor, PipelineCache, SamplerBindingType, ShaderStages, ShaderType, + StorageTextureAccess, TextureFormat, TextureSampleType, UniformBuffer, + binding_types::{sampler, texture_cube, texture_storage_2d, uniform_buffer}, }, renderer::{RenderDevice, RenderQueue}, texture::GpuImage, @@ -26,7 +25,11 @@ pub struct TracerLabel; #[derive(Resource, Reflect, ExtractResource, Clone)] #[reflect(Resource)] -pub struct TracerRenderTextures(pub Handle, pub Handle); +pub struct TracerRenderTextures { + pub main: Handle, + pub secondary: Handle, + pub skybox: Handle, +} #[derive(Resource, Clone, ExtractResource, ShaderType, Default)] pub struct TracerUniforms { @@ -64,10 +67,10 @@ impl Plugin for TracerPipelinePlugin { } fn switch_textures(images: Res, mut sprite: Single<&mut Sprite>) { - if sprite.image == images.0 { - sprite.image = images.1.clone(); + if sprite.image == images.main { + sprite.image = images.secondary.clone(); } else { - sprite.image = images.0.clone(); + sprite.image = images.main.clone(); } } @@ -90,6 +93,8 @@ impl FromWorld for TracerPipeline { texture_storage_2d(TextureFormat::Rgba32Float, StorageTextureAccess::ReadOnly), texture_storage_2d(TextureFormat::Rgba32Float, StorageTextureAccess::WriteOnly), uniform_buffer::(false), + texture_cube(TextureSampleType::Float { filterable: true }), + sampler(SamplerBindingType::Filtering), ), ), ); @@ -138,6 +143,8 @@ fn init_pipeline( texture_storage_2d(TextureFormat::Rgba32Float, StorageTextureAccess::ReadOnly), texture_storage_2d(TextureFormat::Rgba32Float, StorageTextureAccess::WriteOnly), uniform_buffer::(false), + texture_cube(TextureSampleType::Float { filterable: true }), + sampler(SamplerBindingType::Filtering), ), ), ); @@ -177,21 +184,12 @@ fn update_tracer_uniforms( rt_camera: Single<(&GlobalTransform, &Camera), With>, ) { let (transform, cam) = rt_camera.into_inner(); - /* - - let clip_from_view = cam.clip_from_view(); - let world_from_clip = clip_from_view.inverse() * transform.compute_matrix().inverse(); - */ let clip_from_view = cam.clip_from_view(); let world_from_clip = transform.compute_matrix() * clip_from_view.inverse(); - // cam.ndc_to_world(camera_transform, ndc) tracer_uniforms.world_from_clip = world_from_clip; tracer_uniforms.world_position = transform.translation(); - - // info!("clip_from_view = {:?}", clip_from_view); - // info!("world_from_clip = {:?}", world_from_clip); } fn prepare_bind_groups( @@ -203,8 +201,9 @@ fn prepare_bind_groups( render_device: Res, queue: Res, ) { - let view_a = gpu_images.get(&tracer_images.0).unwrap(); - let view_b = gpu_images.get(&tracer_images.1).unwrap(); + let view_a = gpu_images.get(&tracer_images.main).unwrap(); + let view_b = gpu_images.get(&tracer_images.secondary).unwrap(); + let skybox = gpu_images.get(&tracer_images.skybox).unwrap(); // Uniform buffer is used here to demonstrate how to set up a uniform in a compute shader // Alternatives such as storage buffers or push constants may be more suitable for your use case @@ -214,12 +213,24 @@ fn prepare_bind_groups( let bind_group_0 = render_device.create_bind_group( None, &pipeline.texture_bind_group_layout, - &BindGroupEntries::sequential((&view_a.texture_view, &view_b.texture_view, &uniform_buffer)), + &BindGroupEntries::sequential(( + &view_a.texture_view, + &view_b.texture_view, + &uniform_buffer, + &skybox.texture_view, + &skybox.sampler, + )), ); let bind_group_1 = render_device.create_bind_group( None, &pipeline.texture_bind_group_layout, - &BindGroupEntries::sequential((&view_b.texture_view, &view_a.texture_view, &uniform_buffer)), + &BindGroupEntries::sequential(( + &view_b.texture_view, + &view_a.texture_view, + &uniform_buffer, + &skybox.texture_view, + &skybox.sampler, + )), ); commands.insert_resource(TracerImageBindGroups([bind_group_0, bind_group_1])); }