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 world_builder;
mod face_toward;
pub use hierarchy::*;
pub use world_builder::*;
pub use face_toward::*;

View file

@ -41,7 +41,7 @@ impl LightRaw {
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();
LightRaw {
proj: proj.to_cols_array_2d(),

View file

@ -7,7 +7,7 @@ use legion::{prelude::*, storage::Component};
#[derive(Default, Debug, Properties)]
pub struct Camera {
pub view_matrix: Mat4,
pub projection_matrix: Mat4,
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) {
for (mut camera, mut camera_projection) in query.iter_mut(world) {
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.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};
pub trait CameraProjection {
fn get_view_matrix(&self) -> Mat4;
fn get_projection_matrix(&self) -> Mat4;
fn update(&mut self, width: usize, height: usize);
}
@ -16,7 +16,7 @@ pub struct 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);
projection
}
@ -55,7 +55,7 @@ pub struct OrthographicProjection {
}
impl CameraProjection for OrthographicProjection {
fn get_view_matrix(&self) -> Mat4 {
fn get_projection_matrix(&self) -> Mat4 {
let projection = Mat4::orthographic_rh(
self.left,
self.right,

View file

@ -7,12 +7,13 @@ use legion::{
systems::{Query, SubWorld},
};
#[derive(Debug)]
pub struct VisibleEntity {
pub entity: Entity,
pub order: FloatOrd,
}
#[derive(Default)]
#[derive(Default, Debug)]
pub struct VisibleEntities {
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 position = transform.value.w_axis().truncate();
// smaller distances are sorted to lower indices by using the negative distance from the camera
FloatOrd(-(camera_position - position).length())
// smaller distances are sorted to lower indices by using the distance from the camera
FloatOrd((camera_position - position).length())
} else {
let order = FloatOrd(no_transform_order);
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
}

View file

@ -81,7 +81,7 @@ impl SystemNode for CameraNode {
};
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(
BufferInfo {

View file

@ -91,17 +91,17 @@ impl Node for MainPassNode {
TextureAttachment::Id(input.get(input_index).unwrap().get_texture().unwrap());
}
for camera_name in self.cameras.iter() {
let visible_entities = if let Some(camera_entity) = active_cameras.get(camera_name) {
world.get_component::<VisibleEntities>(camera_entity).unwrap()
} else {
continue;
};
render_context.begin_pass(
&self.descriptor,
&render_resource_bindings,
&mut |render_pass| {
for camera_name in self.cameras.iter() {
let visible_entities = if let Some(camera_entity) = active_cameras.get(camera_name) {
world.get_component::<VisibleEntities>(camera_entity).unwrap()
} else {
continue;
};
render_context.begin_pass(
&self.descriptor,
&render_resource_bindings,
&mut |render_pass| {
let mut draw_state = DrawState::default();
for visible_entity in visible_entities.iter() {
let draw = if let Some(draw) = world.get_component::<Draw>(visible_entity.entity) {
@ -170,9 +170,9 @@ impl Node for MainPassNode {
}
}
}
},
);
}
}
},
);
}
}

View file

@ -27,7 +27,7 @@ impl Transform {
/// 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.
/// 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)]
pub fn new_sync_disabled(value: Mat4) -> Self {
Transform { value, sync: false }

View file

@ -50,7 +50,7 @@ fn setup(
})
// camera
.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(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),

View file

@ -39,7 +39,7 @@ fn setup(
})
// camera
.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(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),

View file

@ -53,7 +53,7 @@ fn setup(
})
// camera
.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(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),

View file

@ -63,7 +63,7 @@ fn setup(
})
// camera
.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(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),

View file

@ -67,7 +67,7 @@ fn setup(
})
// camera
.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(0.0, 0.0, 0.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 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 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);
}
}
@ -40,7 +42,6 @@ fn setup(
mut materials: ResMut<Assets<StandardMaterial>>,
) {
let cube_handle = meshes.add(Mesh::from(shape::Cube { size: 1.0 }));
command_buffer
.build()
// parent cube
@ -83,7 +84,7 @@ fn setup(
})
// camera
.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(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),

View file

@ -35,7 +35,7 @@ fn setup(
})
// camera
.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(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),

View file

@ -72,7 +72,7 @@ fn setup(
})
// camera
.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, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),

View file

@ -47,7 +47,7 @@ fn setup(
})
// camera
.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(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),

View file

@ -103,7 +103,7 @@ fn setup(
})
// camera
.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(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),

View file

@ -146,7 +146,7 @@ fn setup(
})
// camera
.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(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),

View file

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

View file

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