diff --git a/engine/src/scene/content/components/bounding_box.rs b/engine/src/scene/content/components/bounding_box.rs index 900e993..cea0b97 100644 --- a/engine/src/scene/content/components/bounding_box.rs +++ b/engine/src/scene/content/components/bounding_box.rs @@ -12,6 +12,23 @@ pub struct BoundingBox { } impl BoundingBox { + pub fn init() -> Self { + Self { + min: [f32::INFINITY; 3], + max: [-f32::INFINITY; 3], + } + } + + pub fn check(&mut self, v: Vector3) { + self.min[0] = self.min[0].min(v.x); + self.min[1] = self.min[1].min(v.y); + self.min[2] = self.min[2].min(v.z); + + self.max[0] = self.max[0].max(v.x); + self.max[1] = self.max[1].max(v.y); + self.max[2] = self.max[2].max(v.z); + } + pub fn is_zero(&self) -> bool { self.min[0] == 0.0 && self.min[1] == 0.0 diff --git a/engine/src/scene/rendering/shaders/raytracing/hardware/default/closesthit.rchit b/engine/src/scene/rendering/shaders/raytracing/hardware/default/closesthit.rchit index a465657..9b43d9f 100644 --- a/engine/src/scene/rendering/shaders/raytracing/hardware/default/closesthit.rchit +++ b/engine/src/scene/rendering/shaders/raytracing/hardware/default/closesthit.rchit @@ -111,7 +111,7 @@ void own_implementation() { int miss_shader_index = 0; int sbt_record_stride = 0; float tmin = 0.001; - float tmax = 10000.0; + float tmax = 1000000000.0; vec3 direction = reflect(gl_WorldRayDirectionEXT, normal); @@ -145,7 +145,7 @@ void own_implementation() { int miss_shader_index = 0; int sbt_record_stride = 0; float tmin = 0.001; - float tmax = 10000.0; + float tmax = 1000000000.0; pay_load.depth++; diff --git a/engine/src/scene/rendering/shaders/raytracing/hardware/default/raygen.rgen b/engine/src/scene/rendering/shaders/raytracing/hardware/default/raygen.rgen index 60fdef6..29a219c 100644 --- a/engine/src/scene/rendering/shaders/raytracing/hardware/default/raygen.rgen +++ b/engine/src/scene/rendering/shaders/raytracing/hardware/default/raygen.rgen @@ -41,7 +41,7 @@ void main() int miss_shader_index = 0; int sbt_record_stride = 0; float tmin = 0.001; - float tmax = 10000.0; + float tmax = 1000000000.0; pay_load.depth = 0; diff --git a/examples/free_space/src/celestial_object.rs b/examples/free_space/src/celestial_object.rs index 0dc3c45..20115c1 100644 --- a/examples/free_space/src/celestial_object.rs +++ b/examples/free_space/src/celestial_object.rs @@ -1,3 +1,4 @@ +use core::f32; use std::time::Duration; use anyhow::Result; @@ -8,21 +9,57 @@ use engine::prelude::{ }; use hexasphere::shapes::IcoSphere; +#[derive(Clone, Copy, Debug)] +pub enum CelestialClass { + Sun, + Solid, + Gas, +} + +impl CelestialClass { + /// in g/cm³ + pub fn density(&self) -> f32 { + match self { + // our sun + CelestialClass::Sun => 1.41, + + // earth + CelestialClass::Solid => 5.51, + + // saturn + CelestialClass::Gas => 0.69, + } + } + + pub fn color(&self) -> [f32; 4] { + match self { + CelestialClass::Sun => Color::Yellow.into(), + CelestialClass::Solid => Color::Green.into(), + CelestialClass::Gas => Color::Orange.into(), + } + } +} + pub struct CelestialObject; impl CelestialObject { pub fn new( world: &mut World, + class: CelestialClass, subdivisions: usize, celestial_reference: impl Into>, ) -> Result { let mut entity_object = AssetHandler::create(world).empty_entity(); - let celestial_settings = CelestialObjectSettings::default(); - let draw = Draw::new(vec![Self::create_asset(world, subdivisions)?]); + let mut celestial_settings = CelestialObjectSettings::default(); + celestial_settings.density = class.density(); + + let (mesh, bounding_box) = Self::create_asset(world, class, subdivisions)?; + let draw = Draw::new(vec![mesh]); draw.set_transform(celestial_settings.model_matrix())?; entity_object.insert_component(draw); + entity_object.insert_component(bounding_box); entity_object.insert_component(celestial_settings); if let Some(e) = celestial_reference.into() { @@ -32,13 +69,19 @@ impl CelestialObject { Ok(entity_object) } - fn create_asset(world: &World, subdivisions: usize) -> Result { + fn create_asset( + world: &World, + class: CelestialClass, + subdivisions: usize, + ) -> Result<(AssetMesh, BoundingBox)> { let context = world.resources.get::(); let scene = world.resources.get::(); let command_buffer = CommandBuffer::new_primary() .build(context.device().clone(), context.queue().clone())?; + let (sphere, bounding_box) = Self::create_sphere(subdivisions); + let buffer = { let mut recorder = command_buffer.begin(VkCommandBufferBeginInfo::new( VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, @@ -48,7 +91,7 @@ impl CelestialObject { .set_memory_usage(MemoryUsage::CpuToGpu) .set_usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT) .set_data( - &Self::create_sphere(subdivisions) + &sphere .into_iter() .map(|(v, n)| PositionNormal::new(v, n)) .collect::>(), @@ -83,6 +126,7 @@ impl CelestialObject { None, None, PrimitiveMaterial { + color: class.color(), emissive_factor: [0.65, 0.65, 0.65], metallic_factor: 0.5, roughness_factor: 0.7, @@ -92,35 +136,44 @@ impl CelestialObject { false, )?; - Ok(asset_mesh) + Ok((asset_mesh, bounding_box)) } - fn create_sphere(subdivisions: usize) -> Vec<(Vector3, Vector3)> { + fn create_sphere(subdivisions: usize) -> (Vec<(Vector3, Vector3)>, BoundingBox) { + let mut bounding_box = BoundingBox::init(); let sphere = IcoSphere::new(subdivisions, |_| ()); let points = sphere .raw_points() .into_iter() - .map(|v| Vector3::from(v.to_array())) + .map(|v| { + let v = Vector3::from(v.to_array()); + bounding_box.check(v); + + v + }) .collect::>>(); - sphere - .get_all_indices() - .chunks(3) - .map(|triangle| { - let p1 = points[triangle[0] as usize]; - let p2 = points[triangle[1] as usize]; - let p3 = points[triangle[2] as usize]; + ( + sphere + .get_all_indices() + .chunks(3) + .map(|triangle| { + let p1 = points[triangle[0] as usize]; + let p2 = points[triangle[1] as usize]; + let p3 = points[triangle[2] as usize]; - let v1 = p1 - p2; - let v2 = p1 - p3; + let v1 = p1 - p2; + let v2 = p1 - p3; - let n = v2.cross(v1); + let n = v2.cross(v1); - [(p1, n), (p2, n), (p3, n)] - }) - .flatten() - .collect() + [(p1, n), (p2, n), (p3, n)] + }) + .flatten() + .collect(), + bounding_box, + ) } } @@ -135,8 +188,18 @@ pub struct CelestialObjectSettings { } impl CelestialObjectSettings { - fn model_matrix(&self) -> Matrix4 { - Matrix4::from_translation(self.location) * Matrix4::from_scale(self.radius) + const SCALE: f32 = 0.5; + + fn volume(&self) -> f32 { + (4.0 / 3.0) * f32::consts::PI * self.radius.powi(3) + } + + fn mass(&self) -> f32 { + self.volume() * self.density + } + + pub fn model_matrix(&self) -> Matrix4 { + Matrix4::from_translation(self.location) * Matrix4::from_scale(self.radius * Self::SCALE) } pub fn update( @@ -145,6 +208,10 @@ impl CelestialObjectSettings { draw: &Draw, celestial_object_settings_reference: &CelestialObjectSettings, ) -> Result<()> { + self.last_update = now; + + // TODO: velocity calculation around celestial reference + Ok(()) } } @@ -153,7 +220,7 @@ impl Default for CelestialObjectSettings { fn default() -> Self { Self { location: Vector3::zero(), - radius: 1.0, + radius: 2.0, density: 1.0, velocity: 0.0, diff --git a/examples/free_space/src/game.rs b/examples/free_space/src/game.rs index 633d7e0..4e9c306 100644 --- a/examples/free_space/src/game.rs +++ b/examples/free_space/src/game.rs @@ -8,7 +8,12 @@ use engine::prelude::{ *, }; -use crate::{FREE_CAMERA_CONTROL, celestial_object::CelestialObject}; +use crate::{ + FREE_CAMERA_CONTROL, + celestial_object::{ + CelestialClass, CelestialObject, CelestialObjectSettings, CelestialReference, + }, +}; #[derive(Clone, Copy, Debug)] struct PlayerEntity(Entity); @@ -264,6 +269,20 @@ impl Game { world_builder.add_update("camera_position", 1_000, Self::camera_update, EmptyFilter)?; } + world_builder.add_update( + "celestial velocity update", + 100, + Self::celestial_velocity_update, + (EmptyFilter, EmptyFilter), + )?; + + world_builder.add_update( + "celestial buffer update", + 110, + Self::celestial_buffer_update, + EmptyFilter, + )?; + Ok(()) } @@ -278,7 +297,16 @@ impl Game { // world.resources.insert(player); world.resources.insert(InputSettings::default()); - let example_planet = CelestialObject::new(world, 5, None)?; + let mut example_sun = CelestialObject::new(world, CelestialClass::Sun, 5, None)?; + let sun_settings = example_sun.get_component_mut::()?; + sun_settings.location = vec3(10_000.0, 10_000.0, 0.0); + sun_settings.radius = 1_000.0; + let sun_entity = world.add_entity(example_sun)?; + + let mut example_planet = CelestialObject::new(world, CelestialClass::Solid, 5, sun_entity)?; + let sun_settings = example_planet.get_component_mut::()?; + sun_settings.location.x = 1000.0; + sun_settings.radius = 250.0; world.add_entity(example_planet)?; let context = world.resources.get::(); @@ -325,4 +353,32 @@ impl Game { view.update_buffer() } + + fn celestial_buffer_update( + _: &mut World, + _: Entity, + draw: &mut Draw, + control: &mut CelestialObjectSettings, + ) -> Result<()> { + draw.set_transform(control.model_matrix())?; + + Ok(()) + } + + fn celestial_velocity_update( + world: &mut World, + (_, draw, lhs_control, reference): ( + Entity, + &mut Draw, + &mut CelestialObjectSettings, + &mut CelestialReference, + ), + (rhs_entity, rhs_control): (Entity, &mut CelestialObjectSettings), + ) -> Result<()> { + if reference.entity == rhs_entity { + lhs_control.update(world.now(), draw, rhs_control)?; + } + + Ok(()) + } }