From 275f4a905e7d7d92c406313f01eb97c3ffe14bb9 Mon Sep 17 00:00:00 2001 From: Amatsugu Date: Sun, 7 Sep 2025 12:46:38 -0400 Subject: [PATCH] camera projection wip --- assets/trace.wgsl | 81 +++++++++++++++++++++++++----------------- src/app.rs | 23 ++++++++++-- src/components/mod.rs | 1 + src/components/rt.rs | 4 +++ src/main.rs | 1 + src/render/pipeline.rs | 31 ++++++++++++---- 6 files changed, 100 insertions(+), 41 deletions(-) create mode 100644 src/components/mod.rs create mode 100644 src/components/rt.rs diff --git a/assets/trace.wgsl b/assets/trace.wgsl index d4dc470..46b6d61 100644 --- a/assets/trace.wgsl +++ b/assets/trace.wgsl @@ -5,7 +5,6 @@ @group(0) @binding(2) var config: TracerUniforms; -@group(0) @binding(3) var view: ViewUniform; struct View { view_proj: mat4x4, @@ -16,25 +15,10 @@ struct View { inv_projection: mat4x4, // equic to Unity's _CameraInverseProjection }; -struct ViewUniform { - clip_from_world: mat4x4, - unjittered_clip_from_world: mat4x4, - world_from_clip: mat4x4, - world_from_view: mat4x4, - view_from_world: mat4x4, - clip_from_view: mat4x4, - view_from_clip: mat4x4, - world_position: vec3, - exposure: f32, - viewport: vec4, - frustum: array, 6>, - color_grading: vec4, // simplified for example - mip_bias: f32, - frame_count: u32, -}; - struct TracerUniforms { sky_color: vec4, + world_from_clip: mat4x4, + world_position: vec3, } @compute @workgroup_size(8, 8, 1) @@ -53,17 +37,33 @@ fn update(@builtin(global_invocation_id) invocation_id: vec3) { let size = textureDimensions(output); let loc = vec2(f32(invocation_id.x), f32(invocation_id.y)) / vec2(size.xy); - let ndc = loc * 2.0f - 1.0f; + // let ndc = loc * 2.0f - 1.0f; - var ray = createCameraRay(ndc); + // var ray = createCameraRay(ndc); - var result = vec3(0.0f); + // var result = vec3(0.0f); - var hit = trace(ray); - result += ray.energy * shade(&ray, hit); + // var hit = trace(ray); + // result += ray.energy * shade(&ray, hit); + + // var rayTest = createCameraRay2(ndc); + // let dirColor = (rayTest.direction * 0.5) + vec3(0.5, 0.5, 0.5); + // let color = vec4(dirColor, 1.0); + + let ndc = vec2( + (f32(invocation_id.x) / f32(size.x)) * 2.0 - 1.0, + (f32(invocation_id.y) / f32(size.y)) * 2.0 - 1.0 + ); + + let clip = vec4(ndc, 0.0, 1.0); + let world = config.world_from_clip * clip; + let world_pos = world.xyz / world.w; + + // map directly to color + let color = vec4((world_pos * 0.1) + vec3(0.5), 1.0); - let color = vec4(result , 1.0); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); + textureStore(output, location, color); } @@ -113,19 +113,34 @@ fn createRay(origin: vec3, direction: vec3) -> Ray fn createCameraRay(ndc: vec2) -> Ray { - // let origin = (view.inv_view * vec4(0.0, 0.0, 0.0, 1.0)).xyz; - // let direction_view = (view.inv_projection * vec4(uv, 0.0, 1.0)).xyz; - // let direction = (view.inv_view * vec4(direction_view, 0.0)).xyz; - - let origin = view.world_position; - let target_point = view.world_from_clip * vec4(ndc, 0.0f, 1.0f); + let origin = config.world_position; + let target_point = config.world_from_clip * vec4(ndc, 0.0f, 1.0f); let direction_point = target_point.xyz / target_point.w; let direction = normalize(direction_point - origin); return createRay(origin, direction); } +fn createCameraRay2(ndc: vec2) -> Ray { + // clip points at near and far + let near_clip = vec4(ndc, 0.0, 1.0); + let far_clip = vec4(ndc, 1.0, 1.0); + + // project into world space + let near_world4 = config.world_from_clip * near_clip; + let far_world4 = config.world_from_clip * far_clip; + + let near_world = near_world4.xyz / near_world4.w; + let far_world = far_world4.xyz / far_world4.w; + + // ray starts at near plane, points toward far plane + let origin = near_world; + let direction = normalize(far_world - near_world); + + return createRay(origin, direction); +} + fn createSphere(position: vec3, radius: f32) -> Sphere { var s: Sphere; @@ -139,7 +154,9 @@ fn createSphere(position: vec3, radius: f32) -> Sphere fn intersectSphere(ray: Ray, bestHit: ptr, sphereIndex: u32) { //Sphere sphere = _Spheres[sphereIndex]; - var sphere = createSphere(vec3(0.0), 1.0f); + var sphere = createSphere(vec3(0.0f, 0.0f, -10.0f), 1.0f); + + var d = ray.origin - sphere.position; var p1 = -dot(ray.direction, d); var p2sqr = p1 * p1 - dot(d, d) + sphere.radius * sphere.radius; @@ -209,7 +226,7 @@ fn shade(ray: ptr, hit: RayHit) -> vec3 else { (*ray).energy = vec3(0.0f); - return vec3(0.1f); + return config.sky_color.xyz; // var theta = acos(ray.direction.y) / -PI; // var phi = atan2(ray.direction.x, -ray.direction.z) / -PI * .5f; // return _SkyboxTexture.SampleLevel(sampler_SkyboxTexture, float2(phi, theta), 0).xyz; diff --git a/src/app.rs b/src/app.rs index 055951c..9d3c5c2 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,12 +1,19 @@ use bevy::{ asset::RenderAssetUsages, + math::VectorSpace, prelude::*, - render::render_resource::{Extent3d, TextureDimension, TextureFormat, TextureUsages}, + render::{ + render_resource::{Extent3d, TextureDimension, TextureFormat, TextureUsages}, + view::RenderLayers, + }, window::PrimaryWindow, }; use iyes_perf_ui::prelude::*; -use crate::render::pipeline::{TracerPipelinePlugin, TracerRenderTextures, TracerUniforms}; +use crate::{ + components::rt::RTCamera, + render::pipeline::{TracerPipelinePlugin, TracerRenderTextures, TracerUniforms}, +}; pub struct Blackhole; @@ -18,6 +25,7 @@ impl Plugin for Blackhole { app.add_plugins(TracerPipelinePlugin); app.insert_resource(TracerUniforms { sky_color: LinearRgba::BLUE, + ..default() }); //Perf UI @@ -74,5 +82,16 @@ fn setup(mut commands: Commands, mut images: ResMut>, window: Sing commands.spawn(Camera2d); + commands.spawn(( + // Camera3d::default(), + Projection::Perspective(PerspectiveProjection { + aspect_ratio: size.x as f32 / size.y as f32, + ..default() + }), + RTCamera, + Transform::from_xyz(0.0, 0.0, 5.0).looking_at(Vec3::ZERO, Vec3::Y), + Name::new("RT Camera"), + )); + commands.insert_resource(TracerRenderTextures(img0, img1)); } diff --git a/src/components/mod.rs b/src/components/mod.rs new file mode 100644 index 0000000..807a12f --- /dev/null +++ b/src/components/mod.rs @@ -0,0 +1 @@ +pub mod rt; diff --git a/src/components/rt.rs b/src/components/rt.rs new file mode 100644 index 0000000..fed00f5 --- /dev/null +++ b/src/components/rt.rs @@ -0,0 +1,4 @@ +use bevy::{prelude::*, render::render_resource::encase::private::ShaderType}; + +#[derive(Component)] +pub struct RTCamera; diff --git a/src/main.rs b/src/main.rs index 7271ea9..c98c1a6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ use bevy::window::PresentMode; use bevy_inspector_egui::{bevy_egui::EguiPlugin, quick::WorldInspectorPlugin}; mod app; +pub mod components; mod render; pub const SHADER_ASSET_PATH: &str = "trace.wgsl"; diff --git a/src/render/pipeline.rs b/src/render/pipeline.rs index ae143ed..a89c2f8 100644 --- a/src/render/pipeline.rs +++ b/src/render/pipeline.rs @@ -4,6 +4,7 @@ use bevy::{ prelude::*, render::{ Render, RenderApp, RenderSet, + camera::CameraProjection, extract_resource::{ExtractResource, ExtractResourcePlugin}, render_asset::RenderAssets, render_graph::{RenderGraph, RenderLabel}, @@ -15,11 +16,10 @@ use bevy::{ }, renderer::{RenderDevice, RenderQueue}, texture::GpuImage, - view::{ViewUniform, ViewUniforms}, }, }; -use crate::{SHADER_ASSET_PATH, render::node::TracerNode}; +use crate::{SHADER_ASSET_PATH, components::rt::RTCamera, render::node::TracerNode}; #[derive(Debug, Hash, PartialEq, Eq, Clone, RenderLabel)] pub struct TracerLabel; @@ -31,6 +31,8 @@ pub struct TracerRenderTextures(pub Handle, pub Handle); #[derive(Resource, Clone, ExtractResource, ShaderType, Default)] pub struct TracerUniforms { pub sky_color: LinearRgba, + pub world_from_clip: Mat4, + pub world_position: Vec3, } pub struct TracerPipelinePlugin; @@ -43,6 +45,8 @@ impl Plugin for TracerPipelinePlugin { )); app.init_resource::() .add_systems(Update, switch_textures); + + app.add_systems(First, update_tracer_uniforms); let render_app = app.sub_app_mut(RenderApp); // render_app.add_systems(Startup, init_pipeline); @@ -86,7 +90,6 @@ impl FromWorld for TracerPipeline { texture_storage_2d(TextureFormat::Rgba32Float, StorageTextureAccess::ReadOnly), texture_storage_2d(TextureFormat::Rgba32Float, StorageTextureAccess::WriteOnly), uniform_buffer::(false), - uniform_buffer::(false), ), ), ); @@ -135,7 +138,6 @@ fn init_pipeline( texture_storage_2d(TextureFormat::Rgba32Float, StorageTextureAccess::ReadOnly), texture_storage_2d(TextureFormat::Rgba32Float, StorageTextureAccess::WriteOnly), uniform_buffer::(false), - uniform_buffer::(false), ), ), ); @@ -170,6 +172,24 @@ fn init_pipeline( #[derive(Resource)] pub struct TracerImageBindGroups(pub [BindGroup; 2]); +fn update_tracer_uniforms( + mut tracer_uniforms: ResMut, + rt_camera: Single<(&GlobalTransform, &Projection), With>, +) { + let (transform, projection) = rt_camera.into_inner(); + let view = transform.compute_matrix().inverse(); + let clip_from_view = match projection { + Projection::Perspective(perspective_projection) => perspective_projection.get_clip_from_view(), + _ => unreachable!("This should never happen: Invalid projection type on RT Camera"), + }; + let clip_from_world = clip_from_view * view; + let world_from_clip = clip_from_world.inverse(); + info_once!("world_from_clip = {:?}", world_from_clip); + + tracer_uniforms.world_from_clip = world_from_clip; + tracer_uniforms.world_position = transform.translation(); +} + fn prepare_bind_groups( mut commands: Commands, pipeline: Res, @@ -178,13 +198,10 @@ fn prepare_bind_groups( tracer_uniforms: Res, render_device: Res, queue: Res, - view_uniforms: Res, ) { let view_a = gpu_images.get(&tracer_images.0).unwrap(); let view_b = gpu_images.get(&tracer_images.1).unwrap(); - //Todo: Insert View Uniforms - // 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 let mut uniform_buffer = UniformBuffer::from(tracer_uniforms.into_inner());