Migrate Camera Resource to Component
This commit is contained in:
parent
07056fc0ce
commit
51a3f812fe
4 changed files with 92 additions and 108 deletions
|
@ -1,6 +1,6 @@
|
|||
use std::{f32::consts::FRAC_PI_2, sync::Arc};
|
||||
use std::sync::Arc;
|
||||
|
||||
use bevy_ecs::resource::Resource;
|
||||
use bevy_ecs::component::Component;
|
||||
use glam::{Mat4, Vec3, Vec4};
|
||||
use vulkano::{
|
||||
Validated,
|
||||
|
@ -8,8 +8,6 @@ use vulkano::{
|
|||
memory::allocator::StandardMemoryAllocator,
|
||||
};
|
||||
|
||||
use crate::core::{input::InputManager, timer::Timer};
|
||||
|
||||
use super::{AsUniformBuffer, mvp::Mvp};
|
||||
|
||||
// See docs/OPENGL_VULKAN_DIFF.md
|
||||
|
@ -20,24 +18,25 @@ const OPENGL_TO_VULKAN_Y_AXIS_FLIP: Mat4 = Mat4 {
|
|||
w_axis: Vec4::new(0.0, 0.0, 0.0, 1.0),
|
||||
};
|
||||
|
||||
#[derive(Resource)]
|
||||
#[derive(Component)]
|
||||
pub struct Camera3D {
|
||||
projection: Mat4,
|
||||
|
||||
position: Vec3,
|
||||
rotation: Vec3,
|
||||
aspect_ratio: f32,
|
||||
fov: f32,
|
||||
near: f32,
|
||||
far: f32,
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct Camera3DTransform {
|
||||
pub position: Vec3,
|
||||
pub rotation: Vec3,
|
||||
}
|
||||
|
||||
impl Camera3D {
|
||||
pub fn new(aspect_ratio: f32, fov: f32, near: f32, far: f32) -> Self {
|
||||
Self {
|
||||
projection: Mat4::perspective_rh(fov, aspect_ratio, near, far),
|
||||
position: Vec3::ZERO,
|
||||
rotation: Vec3::ZERO,
|
||||
aspect_ratio,
|
||||
fov,
|
||||
near,
|
||||
|
@ -45,42 +44,6 @@ impl Camera3D {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn update(
|
||||
&mut self,
|
||||
input_manager: &InputManager,
|
||||
timer: &Timer,
|
||||
movement_speed: f32,
|
||||
camera_sensitivity: f32,
|
||||
) {
|
||||
// Process camera rotation
|
||||
let camera_delta = camera_sensitivity * timer.delta_time();
|
||||
self.rotation += Vec3::new(
|
||||
(input_manager.get_virtual_input_state("mouse_y") * camera_delta).to_radians(),
|
||||
(input_manager.get_virtual_input_state("mouse_x") * camera_delta).to_radians(),
|
||||
0.0,
|
||||
);
|
||||
|
||||
if self.rotation.x > FRAC_PI_2 {
|
||||
self.rotation = Vec3::new(FRAC_PI_2, self.rotation.y, 0.0);
|
||||
}
|
||||
|
||||
if self.rotation.x < -FRAC_PI_2 {
|
||||
self.rotation = Vec3::new(-FRAC_PI_2, self.rotation.y, 0.0);
|
||||
}
|
||||
|
||||
let movement_delta = movement_speed * timer.delta_time();
|
||||
|
||||
let (yaw_sin, yaw_cos) = self.rotation.y.sin_cos();
|
||||
let forward = Vec3::new(yaw_cos, 0.0, yaw_sin).normalize();
|
||||
let right = Vec3::new(-yaw_sin, 0.0, yaw_cos).normalize();
|
||||
|
||||
let tx = input_manager.get_virtual_input_state("move_right") * movement_delta;
|
||||
self.position += tx * right;
|
||||
|
||||
let tz = input_manager.get_virtual_input_state("move_forward") * movement_delta;
|
||||
self.position += tz * forward;
|
||||
}
|
||||
|
||||
pub fn update_projection(&mut self, window_aspect_ratio: f32) {
|
||||
if self.aspect_ratio != window_aspect_ratio {
|
||||
self.aspect_ratio = window_aspect_ratio;
|
||||
|
@ -93,23 +56,16 @@ impl Camera3D {
|
|||
self.projection = projection;
|
||||
}
|
||||
|
||||
pub fn get_position(&self) -> Vec3 {
|
||||
self.position
|
||||
}
|
||||
|
||||
pub fn get_rotation(&self) -> Vec3 {
|
||||
self.rotation
|
||||
}
|
||||
|
||||
pub fn create_buffer(
|
||||
&self,
|
||||
transform: &Camera3DTransform,
|
||||
memory_allocator: &Arc<StandardMemoryAllocator>,
|
||||
) -> Result<Subbuffer<[Mvp]>, Validated<AllocateBufferError>> {
|
||||
let (sin_pitch, cos_pitch) = self.rotation.x.sin_cos();
|
||||
let (sin_yaw, cos_yaw) = self.rotation.y.sin_cos();
|
||||
let (sin_pitch, cos_pitch) = transform.rotation.x.sin_cos();
|
||||
let (sin_yaw, cos_yaw) = transform.rotation.y.sin_cos();
|
||||
|
||||
let view_matrix = Mat4::look_to_rh(
|
||||
self.position,
|
||||
transform.position,
|
||||
Vec3::new(cos_pitch * cos_yaw, sin_pitch, cos_pitch * sin_yaw).normalize(),
|
||||
Vec3::Y,
|
||||
);
|
||||
|
|
|
@ -46,30 +46,6 @@ impl Transform {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn rotate(&mut self, rotation: Quat) {
|
||||
self.rotation *= rotation;
|
||||
}
|
||||
|
||||
pub fn translate(&mut self, translation: Vec3) {
|
||||
self.position += translation;
|
||||
}
|
||||
|
||||
pub fn scale(&mut self, scale: Vec3) {
|
||||
self.scale *= scale;
|
||||
}
|
||||
|
||||
pub fn set_position(&mut self, position: Vec3) {
|
||||
self.position = position;
|
||||
}
|
||||
|
||||
pub fn set_rotation(&mut self, rotation: Quat) {
|
||||
self.rotation = rotation;
|
||||
}
|
||||
|
||||
pub fn set_scale(&mut self, scale: Vec3) {
|
||||
self.scale = scale;
|
||||
}
|
||||
|
||||
/// Get the transformation matrix (immutable - recalculates each time)
|
||||
pub fn matrix(&self) -> Mat4 {
|
||||
Mat4::from_translation(self.position)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use bevy_ecs::prelude::*;
|
||||
use glam::Vec3;
|
||||
|
||||
#[derive(Component, Debug, Clone)]
|
||||
#[derive(Component, Debug, Clone, Default)]
|
||||
pub struct Velocity {
|
||||
pub linear: Vec3,
|
||||
pub angular: Vec3,
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::core::app::DEPTH_IMAGE_ID;
|
|||
use crate::core::app::context::WindowContext;
|
||||
use crate::core::app::user_event::UserEvent;
|
||||
use crate::core::input::InputManagerResource;
|
||||
use crate::core::render::primitives::camera::Camera3D;
|
||||
use crate::core::render::primitives::camera::{Camera3D, Camera3DTransform};
|
||||
use crate::core::render::primitives::transform::Transform;
|
||||
use crate::core::render::primitives::velocity::Velocity;
|
||||
use crate::core::render::primitives::vulkan_resource::{
|
||||
|
@ -49,7 +49,10 @@ pub struct MainSceneState {
|
|||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct CameraSpeed(f32);
|
||||
pub struct MovementSpeed(f32);
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct CameraSensitivity(f32);
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MainScene {
|
||||
|
@ -109,21 +112,31 @@ impl AsScene for MainScene {
|
|||
obj.into_iter().next().unwrap()
|
||||
};
|
||||
|
||||
let camera = window_context.with_renderer(|renderer| {
|
||||
world.spawn((
|
||||
Camera3D::new(
|
||||
renderer.aspect_ratio(),
|
||||
window_context.get_aspect_ratio(),
|
||||
std::f32::consts::FRAC_PI_2,
|
||||
0.01,
|
||||
1000.0,
|
||||
)
|
||||
});
|
||||
world.insert_resource(CameraSpeed(50.0));
|
||||
world.insert_resource(camera);
|
||||
),
|
||||
Camera3DTransform {
|
||||
position: Vec3::ZERO,
|
||||
rotation: Vec3::ZERO,
|
||||
},
|
||||
));
|
||||
|
||||
world.insert_resource(MovementSpeed(50.0));
|
||||
world.insert_resource(CameraSensitivity(10.0));
|
||||
|
||||
let mut scheduler = Schedule::default();
|
||||
scheduler.add_systems(update_velocity_system);
|
||||
scheduler.add_systems(update_timer_system);
|
||||
scheduler.add_systems(update_camera_system);
|
||||
scheduler.add_systems(
|
||||
(
|
||||
update_camera_system,
|
||||
update_velocity_system,
|
||||
update_timer_system,
|
||||
)
|
||||
.chain(),
|
||||
);
|
||||
world.insert_resource(Timer::new());
|
||||
Self::create_entities(world, 100, 10.0, 10.0);
|
||||
|
||||
|
@ -144,7 +157,7 @@ impl AsScene for MainScene {
|
|||
let state = self.state.as_mut().unwrap();
|
||||
|
||||
{
|
||||
let mut camera = world.resource_mut::<Camera3D>();
|
||||
let mut camera = world.query::<&mut Camera3D>().single_mut(world).unwrap();
|
||||
camera.update_projection(window_context.get_aspect_ratio());
|
||||
}
|
||||
|
||||
|
@ -212,11 +225,18 @@ impl AsScene for MainScene {
|
|||
}
|
||||
|
||||
// Create camera uniform using the actual camera
|
||||
let camera_uniform = Arc::new(
|
||||
world
|
||||
.resource::<Camera3D>()
|
||||
.create_buffer(VulkanMemoryAllocator::get_from_world(world))?,
|
||||
);
|
||||
let camera_uniform = {
|
||||
let result = world
|
||||
.query_filtered::<(&Camera3D, &Camera3DTransform), With<Camera3D>>()
|
||||
.single(&world)
|
||||
.unwrap();
|
||||
|
||||
Arc::new(
|
||||
result
|
||||
.0
|
||||
.create_buffer(result.1, VulkanMemoryAllocator::get_from_world(world))?,
|
||||
)
|
||||
};
|
||||
let square_transforms = world
|
||||
.query_filtered::<&Transform, With<Square>>()
|
||||
.iter(&world)
|
||||
|
@ -286,7 +306,10 @@ impl AsScene for MainScene {
|
|||
let delta_time = window_context.get_delta_time();
|
||||
let window_id = window_context.window_id;
|
||||
let window_size = window_context.get_window_size();
|
||||
let camera = world.resource::<Camera3D>();
|
||||
let camera_transform = world
|
||||
.query_filtered::<&Camera3DTransform, With<Camera3D>>()
|
||||
.single(&world)
|
||||
.unwrap();
|
||||
let render_future = window_context.with_gui_mut(|gui| {
|
||||
gui.immediate_ui(|gui| {
|
||||
let ctx = gui.context();
|
||||
|
@ -318,7 +341,7 @@ impl AsScene for MainScene {
|
|||
ui.separator();
|
||||
|
||||
ui.label("Position caméra:");
|
||||
let position = camera.get_position();
|
||||
let position = camera_transform.position;
|
||||
ui.label(format!(" X: {:.2}", position[0]));
|
||||
ui.label(format!(" Y: {:.2}", position[1]));
|
||||
ui.label(format!(" Z: {:.2}", position[2]));
|
||||
|
@ -326,7 +349,7 @@ impl AsScene for MainScene {
|
|||
ui.separator();
|
||||
|
||||
ui.label("Rotation caméra:");
|
||||
let rotation = camera.get_rotation();
|
||||
let rotation = camera_transform.rotation;
|
||||
ui.label(format!(" Yaw: {:.2}°", rotation.y.to_degrees()));
|
||||
ui.label(format!(" Pitch: {:.2}°", rotation.x.to_degrees()));
|
||||
|
||||
|
@ -415,7 +438,7 @@ fn update_velocity_system(mut query: Query<(&mut Transform, &Velocity)>, time: R
|
|||
let delta_time = time.delta_time();
|
||||
|
||||
// Update linear position
|
||||
transform.translate(velocity.linear * delta_time);
|
||||
transform.position += velocity.linear * delta_time;
|
||||
|
||||
// Update angular rotation
|
||||
let angular_delta = velocity.angular * delta_time;
|
||||
|
@ -425,7 +448,7 @@ fn update_velocity_system(mut query: Query<(&mut Transform, &Velocity)>, time: R
|
|||
angular_delta.y,
|
||||
angular_delta.z,
|
||||
);
|
||||
transform.rotate(rotation_delta);
|
||||
transform.rotation *= rotation_delta;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -434,11 +457,40 @@ fn update_timer_system(mut timer: ResMut<Timer>) {
|
|||
}
|
||||
|
||||
fn update_camera_system(
|
||||
mut camera: ResMut<Camera3D>,
|
||||
mut query: Query<&mut Camera3DTransform, With<Camera3D>>,
|
||||
input_manager: Res<InputManagerResource>,
|
||||
timer: Res<Timer>,
|
||||
camera_speed: Res<CameraSpeed>,
|
||||
camera_sensitivity: Res<CameraSensitivity>,
|
||||
movement_speed: Res<MovementSpeed>,
|
||||
time: Res<Timer>,
|
||||
) {
|
||||
let input_manager = input_manager.0.read().unwrap();
|
||||
camera.update(&input_manager, &timer, camera_speed.0, 10.0);
|
||||
let mut camera_transform = query.single_mut().unwrap();
|
||||
|
||||
let delta_time = time.delta_time();
|
||||
|
||||
camera_transform.rotation += Vec3::new(
|
||||
(input_manager.get_virtual_input_state("mouse_y") * camera_sensitivity.0 * delta_time)
|
||||
.to_radians(),
|
||||
(input_manager.get_virtual_input_state("mouse_x") * camera_sensitivity.0 * delta_time)
|
||||
.to_radians(),
|
||||
0.0,
|
||||
);
|
||||
|
||||
if camera_transform.rotation.x > std::f32::consts::FRAC_PI_2 {
|
||||
camera_transform.rotation.x = std::f32::consts::FRAC_PI_2;
|
||||
}
|
||||
|
||||
if camera_transform.rotation.x < -std::f32::consts::FRAC_PI_2 {
|
||||
camera_transform.rotation.x = -std::f32::consts::FRAC_PI_2;
|
||||
}
|
||||
|
||||
let (yaw_sin, yaw_cos) = camera_transform.rotation.y.sin_cos();
|
||||
let forward = Vec3::new(yaw_cos, 0.0, yaw_sin).normalize();
|
||||
let right = Vec3::new(-yaw_sin, 0.0, yaw_cos).normalize();
|
||||
|
||||
let tx = input_manager.get_virtual_input_state("move_right") * movement_speed.0 * delta_time;
|
||||
camera_transform.position += tx * right;
|
||||
|
||||
let tz = input_manager.get_virtual_input_state("move_forward") * movement_speed.0 * delta_time;
|
||||
camera_transform.position += tz * forward;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue