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 glam::{Mat4, Vec3, Vec4};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
Validated,
|
Validated,
|
||||||
|
@ -8,8 +8,6 @@ use vulkano::{
|
||||||
memory::allocator::StandardMemoryAllocator,
|
memory::allocator::StandardMemoryAllocator,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::core::{input::InputManager, timer::Timer};
|
|
||||||
|
|
||||||
use super::{AsUniformBuffer, mvp::Mvp};
|
use super::{AsUniformBuffer, mvp::Mvp};
|
||||||
|
|
||||||
// See docs/OPENGL_VULKAN_DIFF.md
|
// 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),
|
w_axis: Vec4::new(0.0, 0.0, 0.0, 1.0),
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Component)]
|
||||||
pub struct Camera3D {
|
pub struct Camera3D {
|
||||||
projection: Mat4,
|
projection: Mat4,
|
||||||
|
|
||||||
position: Vec3,
|
|
||||||
rotation: Vec3,
|
|
||||||
aspect_ratio: f32,
|
aspect_ratio: f32,
|
||||||
fov: f32,
|
fov: f32,
|
||||||
near: f32,
|
near: f32,
|
||||||
far: f32,
|
far: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct Camera3DTransform {
|
||||||
|
pub position: Vec3,
|
||||||
|
pub rotation: Vec3,
|
||||||
|
}
|
||||||
|
|
||||||
impl Camera3D {
|
impl Camera3D {
|
||||||
pub fn new(aspect_ratio: f32, fov: f32, near: f32, far: f32) -> Self {
|
pub fn new(aspect_ratio: f32, fov: f32, near: f32, far: f32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
projection: Mat4::perspective_rh(fov, aspect_ratio, near, far),
|
projection: Mat4::perspective_rh(fov, aspect_ratio, near, far),
|
||||||
position: Vec3::ZERO,
|
|
||||||
rotation: Vec3::ZERO,
|
|
||||||
aspect_ratio,
|
aspect_ratio,
|
||||||
fov,
|
fov,
|
||||||
near,
|
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) {
|
pub fn update_projection(&mut self, window_aspect_ratio: f32) {
|
||||||
if self.aspect_ratio != window_aspect_ratio {
|
if self.aspect_ratio != window_aspect_ratio {
|
||||||
self.aspect_ratio = window_aspect_ratio;
|
self.aspect_ratio = window_aspect_ratio;
|
||||||
|
@ -93,23 +56,16 @@ impl Camera3D {
|
||||||
self.projection = projection;
|
self.projection = projection;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_position(&self) -> Vec3 {
|
|
||||||
self.position
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_rotation(&self) -> Vec3 {
|
|
||||||
self.rotation
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_buffer(
|
pub fn create_buffer(
|
||||||
&self,
|
&self,
|
||||||
|
transform: &Camera3DTransform,
|
||||||
memory_allocator: &Arc<StandardMemoryAllocator>,
|
memory_allocator: &Arc<StandardMemoryAllocator>,
|
||||||
) -> Result<Subbuffer<[Mvp]>, Validated<AllocateBufferError>> {
|
) -> Result<Subbuffer<[Mvp]>, Validated<AllocateBufferError>> {
|
||||||
let (sin_pitch, cos_pitch) = self.rotation.x.sin_cos();
|
let (sin_pitch, cos_pitch) = transform.rotation.x.sin_cos();
|
||||||
let (sin_yaw, cos_yaw) = self.rotation.y.sin_cos();
|
let (sin_yaw, cos_yaw) = transform.rotation.y.sin_cos();
|
||||||
|
|
||||||
let view_matrix = Mat4::look_to_rh(
|
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::new(cos_pitch * cos_yaw, sin_pitch, cos_pitch * sin_yaw).normalize(),
|
||||||
Vec3::Y,
|
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)
|
/// Get the transformation matrix (immutable - recalculates each time)
|
||||||
pub fn matrix(&self) -> Mat4 {
|
pub fn matrix(&self) -> Mat4 {
|
||||||
Mat4::from_translation(self.position)
|
Mat4::from_translation(self.position)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use glam::Vec3;
|
use glam::Vec3;
|
||||||
|
|
||||||
#[derive(Component, Debug, Clone)]
|
#[derive(Component, Debug, Clone, Default)]
|
||||||
pub struct Velocity {
|
pub struct Velocity {
|
||||||
pub linear: Vec3,
|
pub linear: Vec3,
|
||||||
pub angular: 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::context::WindowContext;
|
||||||
use crate::core::app::user_event::UserEvent;
|
use crate::core::app::user_event::UserEvent;
|
||||||
use crate::core::input::InputManagerResource;
|
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::transform::Transform;
|
||||||
use crate::core::render::primitives::velocity::Velocity;
|
use crate::core::render::primitives::velocity::Velocity;
|
||||||
use crate::core::render::primitives::vulkan_resource::{
|
use crate::core::render::primitives::vulkan_resource::{
|
||||||
|
@ -49,7 +49,10 @@ pub struct MainSceneState {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
pub struct CameraSpeed(f32);
|
pub struct MovementSpeed(f32);
|
||||||
|
|
||||||
|
#[derive(Resource)]
|
||||||
|
pub struct CameraSensitivity(f32);
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct MainScene {
|
pub struct MainScene {
|
||||||
|
@ -109,21 +112,31 @@ impl AsScene for MainScene {
|
||||||
obj.into_iter().next().unwrap()
|
obj.into_iter().next().unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
let camera = window_context.with_renderer(|renderer| {
|
world.spawn((
|
||||||
Camera3D::new(
|
Camera3D::new(
|
||||||
renderer.aspect_ratio(),
|
window_context.get_aspect_ratio(),
|
||||||
std::f32::consts::FRAC_PI_2,
|
std::f32::consts::FRAC_PI_2,
|
||||||
0.01,
|
0.01,
|
||||||
1000.0,
|
1000.0,
|
||||||
)
|
),
|
||||||
});
|
Camera3DTransform {
|
||||||
world.insert_resource(CameraSpeed(50.0));
|
position: Vec3::ZERO,
|
||||||
world.insert_resource(camera);
|
rotation: Vec3::ZERO,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
|
||||||
|
world.insert_resource(MovementSpeed(50.0));
|
||||||
|
world.insert_resource(CameraSensitivity(10.0));
|
||||||
|
|
||||||
let mut scheduler = Schedule::default();
|
let mut scheduler = Schedule::default();
|
||||||
scheduler.add_systems(update_velocity_system);
|
scheduler.add_systems(
|
||||||
scheduler.add_systems(update_timer_system);
|
(
|
||||||
scheduler.add_systems(update_camera_system);
|
update_camera_system,
|
||||||
|
update_velocity_system,
|
||||||
|
update_timer_system,
|
||||||
|
)
|
||||||
|
.chain(),
|
||||||
|
);
|
||||||
world.insert_resource(Timer::new());
|
world.insert_resource(Timer::new());
|
||||||
Self::create_entities(world, 100, 10.0, 10.0);
|
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 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());
|
camera.update_projection(window_context.get_aspect_ratio());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,11 +225,18 @@ impl AsScene for MainScene {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create camera uniform using the actual camera
|
// Create camera uniform using the actual camera
|
||||||
let camera_uniform = Arc::new(
|
let camera_uniform = {
|
||||||
world
|
let result = world
|
||||||
.resource::<Camera3D>()
|
.query_filtered::<(&Camera3D, &Camera3DTransform), With<Camera3D>>()
|
||||||
.create_buffer(VulkanMemoryAllocator::get_from_world(world))?,
|
.single(&world)
|
||||||
);
|
.unwrap();
|
||||||
|
|
||||||
|
Arc::new(
|
||||||
|
result
|
||||||
|
.0
|
||||||
|
.create_buffer(result.1, VulkanMemoryAllocator::get_from_world(world))?,
|
||||||
|
)
|
||||||
|
};
|
||||||
let square_transforms = world
|
let square_transforms = world
|
||||||
.query_filtered::<&Transform, With<Square>>()
|
.query_filtered::<&Transform, With<Square>>()
|
||||||
.iter(&world)
|
.iter(&world)
|
||||||
|
@ -286,7 +306,10 @@ impl AsScene for MainScene {
|
||||||
let delta_time = window_context.get_delta_time();
|
let delta_time = window_context.get_delta_time();
|
||||||
let window_id = window_context.window_id;
|
let window_id = window_context.window_id;
|
||||||
let window_size = window_context.get_window_size();
|
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| {
|
let render_future = window_context.with_gui_mut(|gui| {
|
||||||
gui.immediate_ui(|gui| {
|
gui.immediate_ui(|gui| {
|
||||||
let ctx = gui.context();
|
let ctx = gui.context();
|
||||||
|
@ -318,7 +341,7 @@ impl AsScene for MainScene {
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
||||||
ui.label("Position caméra:");
|
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!(" X: {:.2}", position[0]));
|
||||||
ui.label(format!(" Y: {:.2}", position[1]));
|
ui.label(format!(" Y: {:.2}", position[1]));
|
||||||
ui.label(format!(" Z: {:.2}", position[2]));
|
ui.label(format!(" Z: {:.2}", position[2]));
|
||||||
|
@ -326,7 +349,7 @@ impl AsScene for MainScene {
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
||||||
ui.label("Rotation caméra:");
|
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!(" Yaw: {:.2}°", rotation.y.to_degrees()));
|
||||||
ui.label(format!(" Pitch: {:.2}°", rotation.x.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();
|
let delta_time = time.delta_time();
|
||||||
|
|
||||||
// Update linear position
|
// Update linear position
|
||||||
transform.translate(velocity.linear * delta_time);
|
transform.position += velocity.linear * delta_time;
|
||||||
|
|
||||||
// Update angular rotation
|
// Update angular rotation
|
||||||
let angular_delta = velocity.angular * delta_time;
|
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.y,
|
||||||
angular_delta.z,
|
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(
|
fn update_camera_system(
|
||||||
mut camera: ResMut<Camera3D>,
|
mut query: Query<&mut Camera3DTransform, With<Camera3D>>,
|
||||||
input_manager: Res<InputManagerResource>,
|
input_manager: Res<InputManagerResource>,
|
||||||
timer: Res<Timer>,
|
camera_sensitivity: Res<CameraSensitivity>,
|
||||||
camera_speed: Res<CameraSpeed>,
|
movement_speed: Res<MovementSpeed>,
|
||||||
|
time: Res<Timer>,
|
||||||
) {
|
) {
|
||||||
let input_manager = input_manager.0.read().unwrap();
|
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