First entities render with ecs

This commit is contained in:
Florian RICHER 2025-06-11 23:21:06 +02:00
parent 9fabacffc9
commit 37467d5066
Signed by: florian.richer
GPG key ID: C73D37CBED7BFC77
5 changed files with 148 additions and 117 deletions

View file

@ -1,6 +1,6 @@
use std::sync::Arc; use std::sync::Arc;
use bevy_ecs::resource::Resource; use bevy_ecs::prelude::*;
use glam::{Mat4, Quat, Vec3}; use glam::{Mat4, Quat, Vec3};
use vulkano::{ use vulkano::{
Validated, Validated,
@ -13,7 +13,7 @@ use crate::core::render::primitives::{AsBindableBuffer, AsVertexBuffer};
use super::command::AsRenderableMeshInstance; use super::command::AsRenderableMeshInstance;
#[derive(Resource, Debug, Clone)] #[derive(Component, Debug, Clone)]
pub struct Transform { pub struct Transform {
pub position: Vec3, pub position: Vec3,
pub rotation: Quat, pub rotation: Quat,

View file

@ -1,7 +1,7 @@
use bevy_ecs::resource::Resource; use bevy_ecs::prelude::*;
use glam::Vec3; use glam::Vec3;
#[derive(Resource, Debug, Clone)] #[derive(Component, Debug, Clone)]
pub struct Velocity { pub struct Velocity {
pub linear: Vec3, pub linear: Vec3,
pub angular: Vec3, pub angular: Vec3,

View file

@ -33,60 +33,29 @@ impl SceneManager {
fn create_world_with_resources(window_context: &WindowContext) -> World { fn create_world_with_resources(window_context: &WindowContext) -> World {
let mut world = World::new(); let mut world = World::new();
// Add Vulkan resources let vulkan_context = window_context.vulkan_context();
world.insert_resource(VulkanInstance( let vulkano_context = vulkan_context.vulkano_context();
window_context
.vulkan_context() let vulkan_instance = vulkano_context.instance();
.vulkano_context() let vulkan_device = vulkano_context.device();
.instance() let vulkan_graphics_queue = vulkano_context.graphics_queue();
.clone(), let vulkan_compute_queue = vulkano_context.compute_queue();
)); let vulkan_transfer_queue = vulkano_context.transfer_queue();
world.insert_resource(VulkanDevice( let vulkan_memory_allocator = vulkano_context.memory_allocator();
window_context let vulkan_command_buffer_allocator = vulkan_context.command_buffer_allocator();
.vulkan_context() let vulkan_descriptor_set_allocator = vulkan_context.descriptor_set_allocator();
.vulkano_context()
.device() world.insert_resource(VulkanInstance(vulkan_instance.clone()));
.clone(), world.insert_resource(VulkanDevice(vulkan_device.clone()));
)); world.insert_resource(VulkanGraphicsQueue(vulkan_graphics_queue.clone()));
world.insert_resource(VulkanGraphicsQueue( world.insert_resource(VulkanComputeQueue(vulkan_compute_queue.clone()));
window_context world.insert_resource(VulkanTransferQueue(vulkan_transfer_queue.cloned()));
.vulkan_context() world.insert_resource(VulkanMemoryAllocator(vulkan_memory_allocator.clone()));
.vulkano_context()
.graphics_queue()
.clone(),
));
world.insert_resource(VulkanComputeQueue(
window_context
.vulkan_context()
.vulkano_context()
.compute_queue()
.clone(),
));
world.insert_resource(VulkanTransferQueue(
window_context
.vulkan_context()
.vulkano_context()
.transfer_queue()
.cloned(),
));
world.insert_resource(VulkanMemoryAllocator(
window_context
.vulkan_context()
.vulkano_context()
.memory_allocator()
.clone(),
));
world.insert_resource(VulkanCommandBufferAllocator( world.insert_resource(VulkanCommandBufferAllocator(
window_context vulkan_command_buffer_allocator.clone(),
.vulkan_context()
.command_buffer_allocator()
.clone(),
)); ));
world.insert_resource(VulkanDescriptorSetAllocator( world.insert_resource(VulkanDescriptorSetAllocator(
window_context vulkan_descriptor_set_allocator.clone(),
.vulkan_context()
.descriptor_set_allocator()
.clone(),
)); ));
world world

View file

@ -1,3 +1,6 @@
use bevy_ecs::resource::Resource;
#[derive(Resource)]
pub struct Timer { pub struct Timer {
start_time: std::time::Instant, start_time: std::time::Instant,
last_time: std::time::Instant, last_time: std::time::Instant,

View file

@ -7,6 +7,7 @@ use crate::core::app::context::WindowContext;
use crate::core::app::user_event::UserEvent; use crate::core::app::user_event::UserEvent;
use crate::core::render::primitives::camera::Camera3D; use crate::core::render::primitives::camera::Camera3D;
use crate::core::render::primitives::transform::Transform; use crate::core::render::primitives::transform::Transform;
use crate::core::render::primitives::velocity::Velocity;
use crate::core::render::primitives::vulkan_resource::{ use crate::core::render::primitives::vulkan_resource::{
VulkanCommandBufferAllocator, VulkanDescriptorSetAllocator, VulkanDevice, VulkanGraphicsQueue, VulkanCommandBufferAllocator, VulkanDescriptorSetAllocator, VulkanDevice, VulkanGraphicsQueue,
VulkanMemoryAllocator, VulkanMemoryAllocator,
@ -17,7 +18,10 @@ use crate::core::render::resources::meshes::{ObjMesh, SquareMesh};
use crate::core::render::resources::pipeline::PipelineLoader; use crate::core::render::resources::pipeline::PipelineLoader;
use crate::core::render::resources::texture::{TextureLoadInfo, TextureLoader, TextureSourceKind}; use crate::core::render::resources::texture::{TextureLoadInfo, TextureLoader, TextureSourceKind};
use crate::core::scene::AsScene; use crate::core::scene::AsScene;
use crate::core::timer::Timer;
use crate::game::assets::pipelines::simple::SimplePipeline; use crate::game::assets::pipelines::simple::SimplePipeline;
use bevy_ecs::prelude::*;
use bevy_ecs::schedule::Schedule;
use bevy_ecs::world::World; use bevy_ecs::world::World;
use egui_winit_vulkano::egui; use egui_winit_vulkano::egui;
use glam::EulerRot; use glam::EulerRot;
@ -31,15 +35,20 @@ use vulkano::{
}; };
use winit::window::CursorGrabMode; use winit::window::CursorGrabMode;
#[derive(Component)]
pub struct Square;
#[derive(Component)]
pub struct Cube;
pub struct MainSceneState { pub struct MainSceneState {
texture_loader: TextureLoader, texture_loader: TextureLoader,
pipeline_loader: PipelineLoader, pipeline_loader: PipelineLoader,
square: SquareMesh, square: SquareMesh,
obj: ObjMesh, obj: ObjMesh,
square_instances: Vec<Transform>,
obj_instances: Vec<Transform>,
camera: Camera3D, camera: Camera3D,
speed: f32, speed: f32,
scheduler: Schedule,
} }
#[derive(Default)] #[derive(Default)]
@ -111,45 +120,6 @@ impl AsScene for MainScene {
obj.into_iter().next().unwrap() obj.into_iter().next().unwrap()
}; };
let num_instances = 100;
let instance_size = 10.0;
let instance_spacing = 10.0;
let num_instances_per_row = (num_instances as f32 / instance_spacing).ceil() as u32;
let square_instances: Vec<Transform> = (0..num_instances)
.map(|i| {
Transform::new(
Vec3::new(
(i % num_instances_per_row) as f32 * (instance_spacing + instance_size),
0.0,
(i / num_instances_per_row) as f32 * (instance_spacing + instance_size),
),
Quat::from_euler(EulerRot::XYZ, 0.0, rand::random_range(0.0..=360.0), 0.0),
Vec3::new(instance_size, instance_size, instance_size),
)
})
.collect();
let obj_instances: Vec<Transform> = (0..num_instances)
.map(|i| {
Transform::new(
Vec3::new(
(i % num_instances_per_row) as f32 * (instance_spacing + instance_size),
0.0,
(i / num_instances_per_row) as f32
* (instance_spacing + instance_size)
* -1.0
- instance_spacing * 2.0,
),
Quat::from_euler(EulerRot::XYZ, 0.0, rand::random_range(0.0..=360.0), 0.0),
Vec3::new(
instance_size * 0.5,
instance_size * 0.5,
instance_size * 0.5,
),
)
})
.collect();
let camera = window_context.with_renderer(|renderer| { let camera = window_context.with_renderer(|renderer| {
Camera3D::new( Camera3D::new(
renderer.aspect_ratio(), renderer.aspect_ratio(),
@ -159,14 +129,20 @@ impl AsScene for MainScene {
) )
}); });
let mut scheduler = Schedule::default();
scheduler.add_systems(update_velocity_system);
scheduler.add_systems(update_timer_system);
world.insert_resource(Timer::new());
Self::create_entities(world, 100, 10.0, 10.0);
self.state = Some(MainSceneState { self.state = Some(MainSceneState {
square, square,
obj, obj,
pipeline_loader, pipeline_loader,
square_instances,
obj_instances,
camera, camera,
speed: 50.0, speed: 50.0,
scheduler,
texture_loader, texture_loader,
}); });
@ -175,7 +151,7 @@ impl AsScene for MainScene {
fn update( fn update(
&mut self, &mut self,
_world: &mut World, world: &mut World,
window_context: &WindowContext, window_context: &WindowContext,
) -> Result<(), Box<dyn Error>> { ) -> Result<(), Box<dyn Error>> {
let state = self.state.as_mut().unwrap(); let state = self.state.as_mut().unwrap();
@ -192,20 +168,7 @@ impl AsScene for MainScene {
}); });
}); });
let delta_time = window_context.get_delta_time(); state.scheduler.run(world);
for (i, instance) in state.square_instances.iter_mut().enumerate() {
let rotation_speed = (i % 10) as f32;
let rotation_delta = Quat::from_rotation_y(rotation_speed * delta_time);
instance.rotate(rotation_delta);
}
for (i, instance) in state.obj_instances.iter_mut().enumerate() {
let rotation_speed = (i % 10) as f32;
let rotation_delta = Quat::from_rotation_y(rotation_speed * delta_time);
instance.rotate(rotation_delta);
}
if window_context if window_context
.with_input_manager(|input_manager| input_manager.get_virtual_input_state("mouse_left")) .with_input_manager(|input_manager| input_manager.get_virtual_input_state("mouse_left"))
@ -276,13 +239,23 @@ impl AsScene for MainScene {
.camera .camera
.create_buffer(VulkanMemoryAllocator::get_from_world(world))?, .create_buffer(VulkanMemoryAllocator::get_from_world(world))?,
); );
let square_transforms = world
.query_filtered::<&Transform, With<Square>>()
.iter(&world)
.cloned()
.collect::<Vec<Transform>>();
let square_transform_uniform = Transform::create_buffer( let square_transform_uniform = Transform::create_buffer(
VulkanMemoryAllocator::get_from_world(world), VulkanMemoryAllocator::get_from_world(world),
&state.square_instances, &square_transforms,
)?; )?;
let obj_transform_uniform = Transform::create_buffer( let cube_transforms = world
.query_filtered::<&Transform, With<Cube>>()
.iter(&world)
.cloned()
.collect::<Vec<Transform>>();
let cube_transform_uniform = Transform::create_buffer(
VulkanMemoryAllocator::get_from_world(world), VulkanMemoryAllocator::get_from_world(world),
&state.obj_instances, &cube_transforms,
)?; )?;
state state
@ -309,7 +282,7 @@ impl AsScene for MainScene {
&VulkanDescriptorSetAllocator::get_from_world(world), &VulkanDescriptorSetAllocator::get_from_world(world),
pipeline, pipeline,
&state.obj, &state.obj,
&obj_transform_uniform, &cube_transform_uniform,
vec![ vec![
camera_uniform.clone() as Arc<dyn AsDescriptorSet>, camera_uniform.clone() as Arc<dyn AsDescriptorSet>,
state state
@ -400,3 +373,89 @@ impl AsScene for MainScene {
self.state = None; self.state = None;
} }
} }
impl MainScene {
// Function to create entities in the ECS world
fn create_entities(
world: &mut World,
num_instances: u32,
instance_size: f32,
instance_spacing: f32,
) {
let num_instances_per_row = (num_instances as f32 / instance_spacing).ceil() as u32;
let square_instances = (0..num_instances)
.map(|i| {
let x_index = i % num_instances_per_row;
let z_index = i / num_instances_per_row;
let transform = Transform::new(
Vec3::new(
x_index as f32 * (instance_spacing + instance_size),
0.0,
z_index as f32 * (instance_spacing + instance_size),
),
Quat::from_euler(EulerRot::XYZ, 0.0, rand::random_range(0.0..=360.0), 0.0),
Vec3::new(instance_size, instance_size, instance_size),
);
let velocity = Velocity::new(Vec3::ZERO, Vec3::new(0.0, x_index as f32, 0.0));
(Square, transform, velocity)
})
.collect::<Vec<_>>();
world.spawn_batch(square_instances);
let cube_instances = (0..num_instances)
.map(|i| {
let x_index = i % num_instances_per_row;
let z_index = i / num_instances_per_row;
let transform = Transform::new(
Vec3::new(
x_index as f32 * (instance_spacing + instance_size),
0.0,
z_index as f32 * (instance_spacing + instance_size) * -1.0
- instance_spacing * 2.0,
),
Quat::from_euler(EulerRot::XYZ, 0.0, rand::random_range(0.0..=360.0), 0.0),
Vec3::new(
instance_size * 0.5,
instance_size * 0.5,
instance_size * 0.5,
),
);
let velocity = Velocity::new(Vec3::ZERO, Vec3::new(0.0, x_index as f32, 0.0));
(Cube, transform, velocity)
})
.collect::<Vec<_>>();
world.spawn_batch(cube_instances);
}
}
fn update_velocity_system(mut query: Query<(&mut Transform, &Velocity)>, time: Res<Timer>) {
for (mut transform, velocity) in query.iter_mut() {
let delta_time = time.delta_time();
// Update linear position
transform.translate(velocity.linear * delta_time);
// Update angular rotation
let angular_delta = velocity.angular * delta_time;
let rotation_delta = Quat::from_euler(
EulerRot::XYZ,
angular_delta.x,
angular_delta.y,
angular_delta.z,
);
transform.rotate(rotation_delta);
}
}
fn update_timer_system(mut timer: ResMut<Timer>) {
timer.update();
}