mirror of
https://github.com/bevyengine/bevy
synced 2024-11-25 22:20:20 +00:00
camera: make camera transform in world coordinates instead of the inverse
This commit is contained in:
parent
41dc8a5967
commit
3ee8aa8b0f
22 changed files with 65 additions and 42 deletions
19
crates/bevy_core/src/transform/face_toward.rs
Normal file
19
crates/bevy_core/src/transform/face_toward.rs
Normal 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),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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::*;
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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 }
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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},
|
||||||
|
|
Loading…
Reference in a new issue