diff --git a/simulator/src/main.rs b/simulator/src/main.rs index 8ad7dd5..fd1eaa1 100644 --- a/simulator/src/main.rs +++ b/simulator/src/main.rs @@ -22,7 +22,7 @@ pub async fn run() { radius: 6.371e6, }); - let earth_position = sim.bodies[1].position; + /*let earth_position = sim.bodies[1].position; let earth_velocity = sim.bodies[1].velocity; sim.add_body(Body { @@ -31,7 +31,7 @@ pub async fn run() { velocity: earth_velocity + Vector3::new(0.0, 1022.0, 0.0), mass: 7.342e22, radius: 1.737e6, - }); + });*/ } let sim_clone = simulator.clone(); diff --git a/solar_engine/src/lib.rs b/solar_engine/src/lib.rs index d24fca3..fd742d7 100644 --- a/solar_engine/src/lib.rs +++ b/solar_engine/src/lib.rs @@ -9,6 +9,7 @@ mod renderer; mod instance_manager; mod globals; mod geometry_manager; +mod material; pub use body::Body; diff --git a/solar_engine/src/material.rs b/solar_engine/src/material.rs new file mode 100644 index 0000000..6150ca0 --- /dev/null +++ b/solar_engine/src/material.rs @@ -0,0 +1,58 @@ +use wgpu::{Buffer, Device, Queue}; +use wgpu::util::DeviceExt; +use bytemuck::{Pod, Zeroable}; + +#[repr(C)] +#[derive(Copy, Clone, Pod, Zeroable)] +pub struct GpuMaterial { + pub albedo: [f32; 3], + pub emissive: [f32; 3], + pub metallic: f32, + pub roughness: f32, +} + +pub struct MaterialManager { + materials: Vec, + buffer: Buffer, + pub layout: wgpu::BindGroupLayout, + pub bind_group: wgpu::BindGroup, +} + +impl MaterialManager { + pub fn new(device: &Device, materials: Vec) -> Self { + let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Material Buffer"), + contents: bytemuck::cast_slice(&materials), + usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST, + }); + + let layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("Material BindGroupLayout"), + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Storage { read_only: true }, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }], + }); + + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("Material BindGroup"), + layout: &layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: buffer.as_entire_binding(), + }], + }); + + Self { materials, buffer, layout, bind_group } + } + + pub fn update(&mut self, queue: &Queue) { + queue.write_buffer(&self.buffer, 0, bytemuck::cast_slice(&self.materials)); + } +} \ No newline at end of file diff --git a/solar_engine/src/renderer.rs b/solar_engine/src/renderer.rs index 25673f4..eac8346 100644 --- a/solar_engine/src/renderer.rs +++ b/solar_engine/src/renderer.rs @@ -4,6 +4,7 @@ use crate::globals::GlobalsManager; use crate::instance_manager::InstanceManager; use crate::light::LightManager; use wgpu::{Device, Queue, SurfaceTexture, TextureView}; +use crate::material::MaterialManager; pub struct RenderInstance { pub position: cgmath::Vector3, @@ -77,7 +78,7 @@ impl Vertex { pub struct Renderer { pipeline: wgpu::RenderPipeline, depth_texture: TextureView, - sample_count: u32, + sample_count: u32 } impl Renderer { @@ -86,6 +87,7 @@ impl Renderer { config: &wgpu::SurfaceConfiguration, global_layout: &wgpu::BindGroupLayout, light_manager: &mut LightManager, + material_manager: &MaterialManager, camera: &Camera, sample_count: u32, ) -> Self { @@ -109,6 +111,7 @@ impl Renderer { global_layout, &light_manager.layout, &cluster_buffers.layout, + &material_manager.layout, ], push_constant_ranges: &[], }); @@ -206,6 +209,7 @@ impl Renderer { light_manager: &mut LightManager, geometry: &GeometryManager, instances: &InstanceManager, + material_manager: &mut MaterialManager, ) -> Result<(), wgpu::SurfaceError> { // Update uniform buffer globals.update(queue, camera); @@ -219,6 +223,9 @@ impl Renderer { ); light_manager.update_cluster_buffers(device, queue, &assignment); light_manager.update_gpu(queue); + + // Update material buffer + material_manager.update(queue); let multisampled_texture = device.create_texture(&wgpu::TextureDescriptor { label: Some("Multisample Target"), @@ -274,6 +281,7 @@ impl Renderer { if let Some(clusters) = &light_manager.cluster_buffers { pass.set_bind_group(2, &clusters.bind_group, &[]); } + pass.set_bind_group(3, &material_manager.bind_group, &[]); for shape in geometry.shapes() { if let Some(mesh) = geometry.get(&shape) { diff --git a/solar_engine/src/shaders/shader.wgsl b/solar_engine/src/shaders/shader.wgsl index 2950e7f..eb2c9ae 100644 --- a/solar_engine/src/shaders/shader.wgsl +++ b/solar_engine/src/shaders/shader.wgsl @@ -62,6 +62,17 @@ var cluster_light_indices: array; @group(2) @binding(1) var cluster_offsets: array>; +struct GpuMaterial { + albedo: vec3, + emissive: vec3, + metallic: f32, + roughness: f32, + _pad: vec2, +}; + +@group(3) @binding(0) +var materials: array; + @vertex fn vs_main(vertex: VertexInput, instance: InstanceInput) -> VSOutput { var out: VSOutput; diff --git a/solar_engine/src/simulator.rs b/solar_engine/src/simulator.rs index 6d9c0ec..6bfa553 100644 --- a/solar_engine/src/simulator.rs +++ b/solar_engine/src/simulator.rs @@ -1,6 +1,7 @@ -use std::collections::HashMap; +use std::sync::Mutex; use cgmath::{InnerSpace, Vector3}; use crate::body::Body; +use rayon::prelude::*; const G: f64 = 6.67430e-11; @@ -50,30 +51,40 @@ impl Simulator { let masses: Vec = self.bodies.iter().map(|b| b.mass).collect(); - fn compute_accelerations(states: &[State], masses: &[f64], ownership: &HashMap) -> Vec> { - let mut accels = vec![Vector3::new(0.0, 0.0, 0.0); states.len()]; + fn compute_accelerations(states: &[State], masses: &[f64]) -> Vec> { + let n = states.len(); + let accels = (0..n).map(|_| Mutex::new(Vector3::new(0.0, 0.0, 0.0))).collect::>(); - for (&i, &j) in ownership { - let r = states[j].position - states[i].position; - let dist_sq = r.magnitude2(); - let dist = dist_sq.sqrt(); + (0..n).into_par_iter().for_each(|i| { + for j in (i + 1)..n { + let r = states[j].position - states[i].position; + let dist_sq = r.magnitude2(); + let dist = dist_sq.sqrt(); - if dist < 1e-8 { - continue; + if dist < 1e-8 { + continue; + } + + let force = G * masses[i] * masses[j] / dist_sq; + let accel = force * r / (dist * masses[i]); + let accel_j = -force * r / (dist * masses[j]); + + { + let mut a_i_lock = accels[i].lock().unwrap(); + *a_i_lock += accel; + } + { + let mut a_j_lock = accels[j].lock().unwrap(); + *a_j_lock += accel_j; + } } + }); - let force = G * masses[i] * masses[j] / dist_sq; - let accel = force * r / (dist * masses[i]); - - accels[i] += accel; - } - - accels + accels.into_iter().map(|mutex| mutex.into_inner().unwrap()).collect() } - let ownership = self.compute_soi_owners(); let k1_pos = original_states.iter().map(|s| s.velocity).collect::>(); - let k1_vel = compute_accelerations(&original_states, &masses, &ownership); + let k1_vel = compute_accelerations(&original_states, &masses); let mut temp_states: Vec = original_states.iter().enumerate().map(|(i, s)| { State { @@ -83,7 +94,7 @@ impl Simulator { }).collect(); let k2_pos = temp_states.iter().map(|s| s.velocity).collect::>(); - let k2_vel = compute_accelerations(&temp_states, &masses, &ownership); + let k2_vel = compute_accelerations(&temp_states, &masses); for i in 0..n { temp_states[i].position = original_states[i].position + k2_pos[i] * (dt / 2.0); @@ -91,7 +102,7 @@ impl Simulator { } let k3_pos = temp_states.iter().map(|s| s.velocity).collect::>(); - let k3_vel = compute_accelerations(&temp_states, &masses, &ownership); + let k3_vel = compute_accelerations(&temp_states, &masses); for i in 0..n { temp_states[i].position = original_states[i].position + k3_pos[i] * dt; @@ -99,7 +110,7 @@ impl Simulator { } let k4_pos = temp_states.iter().map(|s| s.velocity).collect::>(); - let k4_vel = compute_accelerations(&temp_states, &masses, &ownership); + let k4_vel = compute_accelerations(&temp_states, &masses); for i in 0..n { let body = &mut self.bodies[i]; @@ -111,33 +122,6 @@ impl Simulator { self.time += dt; } - fn compute_soi_owners(&self) -> HashMap { - let mut ownership = HashMap::new(); - for (i, body) in self.bodies.iter().enumerate() { - let mut min_distance = f64::MAX; - let mut dominant_index = None; - - for (j, other) in self.bodies.iter().enumerate() { - if i == j { - continue; - } - - let r = (body.position - other.position).magnitude(); - let soi_radius = r * (body.mass / other.mass).powf(2.0 / 5.0); - - if r < soi_radius && r < min_distance { - min_distance = r; - dominant_index = Some(j); - } - } - - if let Some(j) = dominant_index { - ownership.insert(i, j); - } - } - ownership - } - pub fn increase_timewarp(&mut self) { if let Some(new) = self.timewarp.checked_mul(2) { if new <= MAX_TIMEWARP { diff --git a/solar_engine/src/state.rs b/solar_engine/src/state.rs index 211a342..cab7f34 100644 --- a/solar_engine/src/state.rs +++ b/solar_engine/src/state.rs @@ -9,6 +9,7 @@ use crate::geometry_manager::GeometryManager; use crate::globals::GlobalsManager; use crate::instance_manager::InstanceManager; use crate::light::{LightManager}; +use crate::material::{GpuMaterial, MaterialManager}; use crate::renderer::{RenderInstance, Renderer}; pub struct SampleCount(pub u32); @@ -34,6 +35,7 @@ pub struct State<'a> { pub geometry_manager: GeometryManager, pub instance_manager: InstanceManager, pub light_manager: LightManager, + pub material_manager: MaterialManager, pub renderer: Renderer, } @@ -64,11 +66,24 @@ impl<'a> State<'a> { let instance_manager = InstanceManager::new(&device); let mut light_manager = LightManager::new(&device, 100); + let initial_materials = vec![ + GpuMaterial { + albedo: [1.0, 1.0, 1.0], + emissive: [0.0, 0.0, 0.0], + metallic: 0.0, + roughness: 0.5, + }; + 8 + ]; + + let mut material_manager = MaterialManager::new(&device, initial_materials); + let renderer = Renderer::new( &device, &config, globals.layout(), &mut light_manager, + &material_manager, &camera, sample_count.get(), ); @@ -86,6 +101,7 @@ impl<'a> State<'a> { geometry_manager, instance_manager, light_manager, + material_manager, renderer, } } @@ -193,7 +209,7 @@ impl<'a> State<'a> { &mut self.light_manager, &self.geometry_manager, &self.instance_manager, - + &mut self.material_manager ) }