camera: make camera transform in world coordinates instead of the inverse

This commit is contained in:
Carter Anderson 2020-06-23 19:15:05 -07:00
parent 41dc8a5967
commit 3ee8aa8b0f
22 changed files with 65 additions and 42 deletions

View file

@ -0,0 +1,19 @@
use glam::{Vec3, Mat4};
pub trait FaceToward {
fn face_toward(eye: Vec3, center: Vec3, up: Vec3) -> Self;
}
impl FaceToward for Mat4 {
fn face_toward(eye: Vec3, center: Vec3, up: Vec3) -> Self {
let forward = (eye - center).normalize();
let right = up.cross(forward).normalize();
let up = forward.cross(right);
Mat4::from_cols(
right.extend(0.0),
up.extend(0.0),
forward.extend(0.0),
eye.extend(1.0),
)
}
}

View file

@ -1,5 +1,7 @@
mod hierarchy; mod hierarchy;
mod world_builder; mod world_builder;
mod face_toward;
pub use hierarchy::*; pub use hierarchy::*;
pub use world_builder::*; pub use world_builder::*;
pub use face_toward::*;

View file

@ -41,7 +41,7 @@ impl LightRaw {
far: light.depth.end, far: light.depth.end,
}; };
let proj = perspective.get_view_matrix() * *transform; let proj = perspective.get_projection_matrix() * *transform;
let (x, y, z) = translation.0.into(); let (x, y, z) = translation.0.into();
LightRaw { LightRaw {
proj: proj.to_cols_array_2d(), proj: proj.to_cols_array_2d(),

View file

@ -7,7 +7,7 @@ use legion::{prelude::*, storage::Component};
#[derive(Default, Debug, Properties)] #[derive(Default, Debug, Properties)]
pub struct Camera { pub struct Camera {
pub view_matrix: Mat4, pub projection_matrix: Mat4,
pub name: Option<String>, pub name: Option<String>,
} }
@ -29,7 +29,7 @@ pub fn camera_system<T: CameraProjection + Component>() -> Box<dyn Schedulable>
if let Some(window) = windows.get(event.id) { if let Some(window) = windows.get(event.id) {
for (mut camera, mut camera_projection) in query.iter_mut(world) { for (mut camera, mut camera_projection) in query.iter_mut(world) {
camera_projection.update(window.width as usize, window.height as usize); camera_projection.update(window.width as usize, window.height as usize);
camera.view_matrix = camera_projection.get_view_matrix(); camera.projection_matrix = camera_projection.get_projection_matrix();
} }
} }
} }
@ -40,7 +40,7 @@ pub fn camera_system<T: CameraProjection + Component>() -> Box<dyn Schedulable>
primary_window_resized_event.width, primary_window_resized_event.width,
primary_window_resized_event.height, primary_window_resized_event.height,
); );
camera.view_matrix = camera_projection.get_view_matrix(); camera.projection_matrix = camera_projection.get_projection_matrix();
} }
} }
}) })

View file

@ -3,7 +3,7 @@ use glam::Mat4;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub trait CameraProjection { pub trait CameraProjection {
fn get_view_matrix(&self) -> Mat4; fn get_projection_matrix(&self) -> Mat4;
fn update(&mut self, width: usize, height: usize); fn update(&mut self, width: usize, height: usize);
} }
@ -16,7 +16,7 @@ pub struct PerspectiveProjection {
} }
impl CameraProjection for PerspectiveProjection { impl CameraProjection for PerspectiveProjection {
fn get_view_matrix(&self) -> Mat4 { fn get_projection_matrix(&self) -> Mat4 {
let projection = Mat4::perspective_rh_gl(self.fov, self.aspect_ratio, self.near, self.far); let projection = Mat4::perspective_rh_gl(self.fov, self.aspect_ratio, self.near, self.far);
projection projection
} }
@ -55,7 +55,7 @@ pub struct OrthographicProjection {
} }
impl CameraProjection for OrthographicProjection { impl CameraProjection for OrthographicProjection {
fn get_view_matrix(&self) -> Mat4 { fn get_projection_matrix(&self) -> Mat4 {
let projection = Mat4::orthographic_rh( let projection = Mat4::orthographic_rh(
self.left, self.left,
self.right, self.right,

View file

@ -7,12 +7,13 @@ use legion::{
systems::{Query, SubWorld}, systems::{Query, SubWorld},
}; };
#[derive(Debug)]
pub struct VisibleEntity { pub struct VisibleEntity {
pub entity: Entity, pub entity: Entity,
pub order: FloatOrd, pub order: FloatOrd,
} }
#[derive(Default)] #[derive(Default, Debug)]
pub struct VisibleEntities { pub struct VisibleEntities {
pub value: Vec<VisibleEntity>, pub value: Vec<VisibleEntity>,
} }
@ -41,8 +42,8 @@ pub fn visible_entities_system(
let order = if let Some(transform) = world.get_component::<Transform>(entity) { let order = if let Some(transform) = world.get_component::<Transform>(entity) {
let position = transform.value.w_axis().truncate(); let position = transform.value.w_axis().truncate();
// smaller distances are sorted to lower indices by using the negative distance from the camera // smaller distances are sorted to lower indices by using the distance from the camera
FloatOrd(-(camera_position - position).length()) FloatOrd((camera_position - position).length())
} else { } else {
let order = FloatOrd(no_transform_order); let order = FloatOrd(no_transform_order);
no_transform_order += 0.1; no_transform_order += 0.1;
@ -54,7 +55,7 @@ pub fn visible_entities_system(
}) })
} }
visible_entities.value.sort_by_key(|e| e.order) visible_entities.value.sort_by_key(|e| e.order);
// TODO: check for big changes in visible entities len() vs capacity() (ex: 2x) and resize to prevent holding unneeded memory // TODO: check for big changes in visible entities len() vs capacity() (ex: 2x) and resize to prevent holding unneeded memory
} }

View file

@ -81,7 +81,7 @@ impl SystemNode for CameraNode {
}; };
let matrix_size = std::mem::size_of::<[[f32; 4]; 4]>(); let matrix_size = std::mem::size_of::<[[f32; 4]; 4]>();
let camera_matrix: [f32; 16] = (camera.view_matrix * transform.value).to_cols_array(); let camera_matrix: [f32; 16] = (camera.projection_matrix * transform.value.inverse()).to_cols_array();
let tmp_buffer = render_resource_context.create_buffer_mapped( let tmp_buffer = render_resource_context.create_buffer_mapped(
BufferInfo { BufferInfo {

View file

@ -91,6 +91,10 @@ impl Node for MainPassNode {
TextureAttachment::Id(input.get(input_index).unwrap().get_texture().unwrap()); TextureAttachment::Id(input.get(input_index).unwrap().get_texture().unwrap());
} }
render_context.begin_pass(
&self.descriptor,
&render_resource_bindings,
&mut |render_pass| {
for camera_name in self.cameras.iter() { for camera_name in self.cameras.iter() {
let visible_entities = if let Some(camera_entity) = active_cameras.get(camera_name) { let visible_entities = if let Some(camera_entity) = active_cameras.get(camera_name) {
world.get_component::<VisibleEntities>(camera_entity).unwrap() world.get_component::<VisibleEntities>(camera_entity).unwrap()
@ -98,10 +102,6 @@ impl Node for MainPassNode {
continue; continue;
}; };
render_context.begin_pass(
&self.descriptor,
&render_resource_bindings,
&mut |render_pass| {
let mut draw_state = DrawState::default(); let mut draw_state = DrawState::default();
for visible_entity in visible_entities.iter() { for visible_entity in visible_entities.iter() {
let draw = if let Some(draw) = world.get_component::<Draw>(visible_entity.entity) { let draw = if let Some(draw) = world.get_component::<Draw>(visible_entity.entity) {
@ -170,10 +170,10 @@ impl Node for MainPassNode {
} }
} }
} }
}
}, },
); );
} }
}
} }
/// Tracks the current pipeline state to ensure draw calls are valid. /// Tracks the current pipeline state to ensure draw calls are valid.

View file

@ -27,7 +27,7 @@ impl Transform {
/// This creates a new `LocalToWorld` transform with the `sync` field set to `false`. /// This creates a new `LocalToWorld` transform with the `sync` field set to `false`.
/// While `sync` is false, position, rotation, and scale components will not be synced to the transform. /// While `sync` is false, position, rotation, and scale components will not be synced to the transform.
/// This is helpful if you want to manually set the transform to a value (ex: Mat4::look_at_rh) /// This is helpful if you want to manually set the transform to a value (ex: Mat4::face_toward)
#[inline(always)] #[inline(always)]
pub fn new_sync_disabled(value: Mat4) -> Self { pub fn new_sync_disabled(value: Mat4) -> Self {
Transform { value, sync: false } Transform { value, sync: false }

View file

@ -50,7 +50,7 @@ fn setup(
}) })
// camera // camera
.add_entity(PerspectiveCameraEntity { .add_entity(PerspectiveCameraEntity {
transform: Transform::new_sync_disabled(Mat4::look_at_rh( transform: Transform::new_sync_disabled(Mat4::face_toward(
Vec3::new(3.0, 8.0, 5.0), Vec3::new(3.0, 8.0, 5.0),
Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0), Vec3::new(0.0, 0.0, 1.0),

View file

@ -39,7 +39,7 @@ fn setup(
}) })
// camera // camera
.add_entity(PerspectiveCameraEntity { .add_entity(PerspectiveCameraEntity {
transform: Transform::new_sync_disabled(Mat4::look_at_rh( transform: Transform::new_sync_disabled(Mat4::face_toward(
Vec3::new(2.0, -6.0, 2.0), Vec3::new(2.0, -6.0, 2.0),
Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0), Vec3::new(0.0, 0.0, 1.0),

View file

@ -53,7 +53,7 @@ fn setup(
}) })
// camera // camera
.add_entity(PerspectiveCameraEntity { .add_entity(PerspectiveCameraEntity {
transform: Transform::new_sync_disabled(Mat4::look_at_rh( transform: Transform::new_sync_disabled(Mat4::face_toward(
Vec3::new(5.0, 10.0, 10.0), Vec3::new(5.0, 10.0, 10.0),
Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0), Vec3::new(0.0, 0.0, 1.0),

View file

@ -63,7 +63,7 @@ fn setup(
}) })
// camera // camera
.add_entity(PerspectiveCameraEntity { .add_entity(PerspectiveCameraEntity {
transform: Transform::new_sync_disabled(Mat4::look_at_rh( transform: Transform::new_sync_disabled(Mat4::face_toward(
Vec3::new(3.0, 8.0, 5.0), Vec3::new(3.0, 8.0, 5.0),
Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0), Vec3::new(0.0, 0.0, 1.0),

View file

@ -67,7 +67,7 @@ fn setup(
}) })
// camera // camera
.add_entity(PerspectiveCameraEntity { .add_entity(PerspectiveCameraEntity {
transform: Transform::new_sync_disabled(Mat4::look_at_rh( transform: Transform::new_sync_disabled(Mat4::face_toward(
Vec3::new(3.0, -8.0, 5.0), Vec3::new(3.0, -8.0, 5.0),
Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0), Vec3::new(0.0, 0.0, 1.0),

View file

@ -24,9 +24,11 @@ fn camera_order_color_system(
) { ) {
for (_camera, visible_entities) in camera_query.iter(world) { for (_camera, visible_entities) in camera_query.iter(world) {
for visible_entity in visible_entities.iter() { for visible_entity in visible_entities.iter() {
if let Some(material_handle) = world.get_component::<Handle<StandardMaterial>>(visible_entity.entity) { if let Some(material_handle) =
world.get_component::<Handle<StandardMaterial>>(visible_entity.entity)
{
let material = materials.get_mut(&material_handle).unwrap(); let material = materials.get_mut(&material_handle).unwrap();
let value = 1.0 - (20.0 + visible_entity.order.0) / 7.0; let value = 1.0 - (visible_entity.order.0 - 10.0) / 7.0;
material.albedo = Color::rgb(value, value, value); material.albedo = Color::rgb(value, value, value);
} }
} }
@ -40,7 +42,6 @@ fn setup(
mut materials: ResMut<Assets<StandardMaterial>>, mut materials: ResMut<Assets<StandardMaterial>>,
) { ) {
let cube_handle = meshes.add(Mesh::from(shape::Cube { size: 1.0 })); let cube_handle = meshes.add(Mesh::from(shape::Cube { size: 1.0 }));
command_buffer command_buffer
.build() .build()
// parent cube // parent cube
@ -83,7 +84,7 @@ fn setup(
}) })
// camera // camera
.add_entity(PerspectiveCameraEntity { .add_entity(PerspectiveCameraEntity {
transform: Transform::new_sync_disabled(Mat4::look_at_rh( transform: Transform::new_sync_disabled(Mat4::face_toward(
Vec3::new(5.0, 10.0, 10.0), Vec3::new(5.0, 10.0, 10.0),
Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0), Vec3::new(0.0, 0.0, 1.0),

View file

@ -35,7 +35,7 @@ fn setup(
}) })
// camera // camera
.add_entity(PerspectiveCameraEntity { .add_entity(PerspectiveCameraEntity {
transform: Transform::new_sync_disabled(Mat4::look_at_rh( transform: Transform::new_sync_disabled(Mat4::face_toward(
Vec3::new(3.0, 8.0, 5.0), Vec3::new(3.0, 8.0, 5.0),
Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0), Vec3::new(0.0, 0.0, 1.0),

View file

@ -72,7 +72,7 @@ fn setup(
}) })
// camera // camera
.add_entity(PerspectiveCameraEntity { .add_entity(PerspectiveCameraEntity {
transform: Transform::new_sync_disabled(Mat4::look_at_rh( transform: Transform::new_sync_disabled(Mat4::face_toward(
Vec3::new(0.0, -10.0, 3.0), Vec3::new(0.0, -10.0, 3.0),
Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0), Vec3::new(0.0, 0.0, 1.0),

View file

@ -47,7 +47,7 @@ fn setup(
}) })
// camera // camera
.add_entity(PerspectiveCameraEntity { .add_entity(PerspectiveCameraEntity {
transform: Transform::new_sync_disabled(Mat4::look_at_rh( transform: Transform::new_sync_disabled(Mat4::face_toward(
Vec3::new(2.0, -6.0, 2.0), Vec3::new(2.0, -6.0, 2.0),
Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0), Vec3::new(0.0, 0.0, 1.0),

View file

@ -103,7 +103,7 @@ fn setup(
}) })
// camera // camera
.add_entity(PerspectiveCameraEntity { .add_entity(PerspectiveCameraEntity {
transform: Transform::new_sync_disabled(Mat4::look_at_rh( transform: Transform::new_sync_disabled(Mat4::face_toward(
Vec3::new(3.0, 8.0, 5.0), Vec3::new(3.0, 8.0, 5.0),
Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0), Vec3::new(0.0, 0.0, 1.0),

View file

@ -146,7 +146,7 @@ fn setup(
}) })
// camera // camera
.add_entity(PerspectiveCameraEntity { .add_entity(PerspectiveCameraEntity {
transform: Transform::new_sync_disabled(Mat4::look_at_rh( transform: Transform::new_sync_disabled(Mat4::face_toward(
Vec3::new(3.0, 8.0, 5.0), Vec3::new(3.0, 8.0, 5.0),
Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0), Vec3::new(0.0, 0.0, 1.0),

View file

@ -48,7 +48,7 @@ fn setup(
// }) // })
// // 3d camera // // 3d camera
// .add_entity(CameraEntity { // .add_entity(CameraEntity {
// transform: Transform(Mat4::look_at_rh( // transform: Transform(Mat4::face_toward(
// Vec3::new(3.0, 8.0, 5.0), // Vec3::new(3.0, 8.0, 5.0),
// Vec3::new(0.0, 0.0, 0.0), // Vec3::new(0.0, 0.0, 0.0),
// Vec3::new(0.0, 0.0, 1.0), // Vec3::new(0.0, 0.0, 1.0),

View file

@ -6,7 +6,7 @@ pub use crate::{
asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle}, asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle},
core::{ core::{
time::{Time, Timer}, time::{Time, Timer},
transform::{CommandBufferBuilderSource, WorldBuilder, WorldBuilderSource}, transform::{CommandBufferBuilderSource, WorldBuilder, WorldBuilderSource, FaceToward},
}, },
diagnostic::DiagnosticsPlugin, diagnostic::DiagnosticsPlugin,
input::{keyboard::KeyCode, mouse::MouseButton, Input}, input::{keyboard::KeyCode, mouse::MouseButton, Input},