camera: break out projection components

This commit is contained in:
Carter Anderson 2020-05-29 17:25:14 -07:00
parent db27d63b91
commit fec9034644
11 changed files with 45 additions and 87 deletions

View file

@ -1,4 +1,4 @@
use bevy_render::{Color, PerspectiveCamera};
use bevy_render::{Color, PerspectiveCamera, CameraProjection};
use bevy_transform::components::Translation;
use bevy_property::Properties;
use glam::Mat4;

View file

@ -1,9 +1,8 @@
use bevy_app::{Events, GetEventReader};
use bevy_property::{Properties, Property};
use bevy_property::Properties;
use bevy_window::WindowResized;
use glam::Mat4;
use legion::prelude::*;
use serde::{Deserialize, Serialize};
use legion::{prelude::*, storage::Component};
#[derive(Default, Properties)]
pub struct ActiveCamera;
@ -11,7 +10,7 @@ pub struct ActiveCamera;
#[derive(Default, Properties)]
pub struct ActiveCamera2d;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Properties)]
pub struct OrthographicCamera {
pub left: f32,
pub right: f32,
@ -21,7 +20,7 @@ pub struct OrthographicCamera {
pub far: f32,
}
impl OrthographicCamera {
impl CameraProjection for OrthographicCamera {
fn get_view_matrix(&self) -> Mat4 {
let projection = Mat4::orthographic_rh_gl(
self.left,
@ -33,6 +32,10 @@ impl OrthographicCamera {
);
projection
}
fn update(&mut self, width: usize, height: usize) {
self.right = width as f32;
self.top = height as f32;
}
}
impl Default for OrthographicCamera {
@ -48,7 +51,12 @@ impl Default for OrthographicCamera {
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub trait CameraProjection {
fn get_view_matrix(&self) -> Mat4;
fn update(&mut self, width: usize, height: usize);
}
#[derive(Debug, Clone, Properties)]
pub struct PerspectiveCamera {
pub fov: f32,
pub aspect_ratio: f32,
@ -56,11 +64,14 @@ pub struct PerspectiveCamera {
pub far: f32,
}
impl PerspectiveCamera {
pub fn get_view_matrix(&self) -> Mat4 {
impl CameraProjection for PerspectiveCamera {
fn get_view_matrix(&self) -> Mat4 {
let projection = Mat4::perspective_rh_gl(self.fov, self.aspect_ratio, self.near, self.far);
projection
}
fn update(&mut self, width: usize, height: usize) {
self.aspect_ratio = width as f32 / height as f32;
}
}
impl Default for PerspectiveCamera {
@ -74,72 +85,24 @@ impl Default for PerspectiveCamera {
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Property)]
pub enum CameraType {
Perspective(PerspectiveCamera),
Orthographic(OrthographicCamera),
}
impl CameraType {
pub fn default_perspective() -> CameraType {
CameraType::Perspective(PerspectiveCamera::default())
}
pub fn default_orthographic() -> CameraType {
CameraType::Orthographic(OrthographicCamera::default())
}
}
impl Default for CameraType {
fn default() -> Self {
CameraType::default_perspective()
}
}
#[derive(Default, Debug, Properties)]
pub struct Camera {
pub view_matrix: Mat4,
pub camera_type: CameraType,
}
impl Camera {
pub fn new(camera_type: CameraType) -> Self {
Camera {
view_matrix: Mat4::identity(),
camera_type,
}
}
pub fn update(&mut self, width: u32, height: u32) {
self.view_matrix = match &mut self.camera_type {
CameraType::Perspective(projection) => {
projection.aspect_ratio = width as f32 / height as f32;
projection.get_view_matrix()
}
CameraType::Orthographic(orthographic) => {
orthographic.right = width as f32;
orthographic.top = height as f32;
orthographic.get_view_matrix()
}
}
}
}
pub fn camera_update_system(resources: &mut Resources) -> Box<dyn Schedulable> {
pub fn camera_system<T: CameraProjection + Component>(resources: &mut Resources) -> Box<dyn Schedulable> {
let mut window_resized_event_reader = resources.get_event_reader::<WindowResized>();
(move |world: &mut SubWorld,
window_resized_events: Res<Events<WindowResized>>,
query: &mut Query<Write<Camera>>| {
query: &mut Query<(Write<Camera>, Write<T>)>| {
let primary_window_resized_event = window_resized_event_reader
.find_latest(&window_resized_events, |event| event.is_primary);
if let Some(primary_window_resized_event) = primary_window_resized_event {
for mut camera in query.iter_mut(world) {
camera.update(
primary_window_resized_event.width,
primary_window_resized_event.height,
);
for (mut camera, mut camera_projection) in query.iter_mut(world) {
camera_projection.update(primary_window_resized_event.width, primary_window_resized_event.height);
camera.view_matrix = camera_projection.get_view_matrix();
}
}
})
.system()
}
}

View file

@ -1,4 +1,4 @@
use crate::{mesh::Mesh, ActiveCamera, ActiveCamera2d, Camera, CameraType, Renderable};
use crate::{mesh::Mesh, ActiveCamera, ActiveCamera2d, Camera, Renderable, OrthographicCamera, PerspectiveCamera};
use bevy_asset::Handle;
use bevy_derive::EntityArchetype;
use bevy_transform::components::{LocalToWorld, Rotation, Scale, Translation};
@ -17,21 +17,14 @@ pub struct MeshMaterialEntity<T: Default + Send + Sync + 'static> {
#[derive(EntityArchetype, Default)]
pub struct CameraEntity {
pub camera: Camera,
pub perspective_camera: PerspectiveCamera,
pub active_camera: ActiveCamera,
pub local_to_world: LocalToWorld,
}
#[derive(EntityArchetype)]
pub struct Camera2dEntity {
#[derive(EntityArchetype, Default)]
pub struct OrthographicCameraEntity {
pub camera: Camera,
pub orthographic_camera: OrthographicCamera,
pub active_camera_2d: ActiveCamera2d,
}
impl Default for Camera2dEntity {
fn default() -> Self {
Camera2dEntity {
camera: Camera::new(CameraType::default_orthographic()),
active_camera_2d: ActiveCamera2d,
}
}
}
}

View file

@ -76,11 +76,12 @@ impl AppPlugin for RenderPlugin {
.add_asset::<PipelineDescriptor>()
.add_asset_loader::<Texture, PngTextureLoader>()
.register_component::<Camera>()
.register_component::<OrthographicCamera>()
.register_component::<PerspectiveCamera>()
.register_component::<Renderable>()
.register_component::<ActiveCamera>()
.register_component::<ActiveCamera2d>()
.register_property_type::<Color>()
.register_property_type::<CameraType>()
.register_property_type::<Range<f32>>()
.init_resource::<RenderGraph>()
.init_resource::<PipelineAssignments>()
@ -91,7 +92,8 @@ impl AppPlugin for RenderPlugin {
.init_resource::<EntitiesWaitingForAssets>()
.init_resource::<TextureResourceSystemState>()
.add_system(entity_render_resource_assignments_system())
.init_system_to_stage(stage::POST_UPDATE, camera::camera_update_system)
.init_system_to_stage(stage::POST_UPDATE, camera::camera_system::<OrthographicCamera>)
.init_system_to_stage(stage::POST_UPDATE, camera::camera_system::<PerspectiveCamera>)
.add_system_to_stage(
stage::PRE_UPDATE,
EntitiesWaitingForAssets::clear_system.system(),

View file

@ -4,8 +4,8 @@ use super::{WindowDescriptor, WindowId};
#[derive(Debug, Clone)]
pub struct WindowResized {
pub id: WindowId,
pub width: u32,
pub height: u32,
pub width: usize,
pub height: usize,
pub is_primary: bool,
}

View file

@ -73,8 +73,8 @@ pub fn winit_runner(mut app: App) {
let mut resize_events = app.resources.get_mut::<Events<WindowResized>>().unwrap();
resize_events.send(WindowResized {
id: window_id,
height: window.height,
width: window.width,
height: window.height as usize,
width: window.width as usize,
is_primary: windows.is_primary(window_id),
});
}

View file

@ -15,7 +15,7 @@ fn setup(
let texture_handle = asset_server.load("assets/branding/icon.png").unwrap();
command_buffer
.build()
.add_entity(Camera2dEntity::default())
.add_entity(OrthographicCameraEntity::default())
.add_entity(SpriteEntity {
rect: Rect {
position: Vec2::new(300.0, 300.0),

View file

@ -25,7 +25,7 @@ fn setup(command_buffer: &mut CommandBuffer, asset_server: Res<AssetServer>) {
command_buffer
.build()
// 2d camera
.add_entity(Camera2dEntity::default())
.add_entity(OrthographicCameraEntity::default())
// texture
.add_entity(LabelEntity {
node: Node::new(

View file

@ -58,7 +58,7 @@ fn setup(
// ..Default::default()
// })
// 2d camera
.add_entity(Camera2dEntity::default())
.add_entity(OrthographicCameraEntity::default())
// left vertical fill
.add_entity(UiEntity {
node: Node::new(

View file

@ -23,7 +23,7 @@ fn placement_system(
fn setup(command_buffer: &mut CommandBuffer, mut materials: ResMut<Assets<ColorMaterial>>) {
let mut builder = command_buffer.build();
builder.add_entity(Camera2dEntity::default());
builder.add_entity(OrthographicCameraEntity::default());
let mut prev = Vec2::default();
let count = 1000;

View file

@ -30,7 +30,7 @@ pub use crate::render::{
render_resource::resource_name,
shader::{Shader, ShaderDefSuffixProvider, ShaderStage, ShaderStages},
texture::{Texture, TextureType},
ActiveCamera, ActiveCamera2d, Camera, CameraType, Color, ColorSource, Renderable,
ActiveCamera, ActiveCamera2d, Camera, OrthographicCamera, PerspectiveCamera, Color, ColorSource, Renderable,
};
#[cfg(feature = "scene")]
pub use crate::scene::{Scene, SceneSpawner};