From 35e22924461d2ff7a3f139969c3e40b71fc4053b Mon Sep 17 00:00:00 2001 From: thatcomputerguy0101 Date: Thu, 24 Oct 2024 14:16:44 -0400 Subject: [PATCH 1/7] Add camera view example (mostly for debugging) --- Cargo.toml | 6 +- examples/camera_view/Cargo.toml | 18 ++ examples/camera_view/src/lib.rs | 19 ++ examples/camera_view/src/main.rs | 414 +++++++++++++++++++++++++++++++ 4 files changed, 456 insertions(+), 1 deletion(-) create mode 100644 examples/camera_view/Cargo.toml create mode 100644 examples/camera_view/src/lib.rs create mode 100644 examples/camera_view/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index 20d7f9e90..fbaf31dba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -202,4 +202,8 @@ required-features = ["headless"] [[example]] name = "logo" -path = "examples/logo/src/main.rs" \ No newline at end of file +path = "examples/logo/src/main.rs" + +[[example]] +name = "camera_view" +path = "examples/camera_view/src/main.rs" diff --git a/examples/camera_view/Cargo.toml b/examples/camera_view/Cargo.toml new file mode 100644 index 000000000..e85fbf70a --- /dev/null +++ b/examples/camera_view/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "camera_view" +version = "0.1.0" +authors = ["Asger Nyman Christiansen ", "Alan Everett "] +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +three-d = { path = "../../", features=["egui-gui"] } + +[target.'cfg(target_arch = "wasm32")'.dependencies] +log = "0.4" +wasm-bindgen = "0.2" +wasm-bindgen-futures = "0.4" +console_error_panic_hook = "0.1" +console_log = "1" diff --git a/examples/camera_view/src/lib.rs b/examples/camera_view/src/lib.rs new file mode 100644 index 000000000..ca78be894 --- /dev/null +++ b/examples/camera_view/src/lib.rs @@ -0,0 +1,19 @@ +#![allow(special_module_name)] +mod main; + +// Entry point for wasm +#[cfg(target_arch = "wasm32")] +use wasm_bindgen::prelude::*; + +#[cfg(target_arch = "wasm32")] +#[wasm_bindgen(start)] +pub fn start() -> Result<(), JsValue> { + console_log::init_with_level(log::Level::Debug).unwrap(); + + use log::info; + info!("Logging works!"); + + std::panic::set_hook(Box::new(console_error_panic_hook::hook)); + main::main(); + Ok(()) +} diff --git a/examples/camera_view/src/main.rs b/examples/camera_view/src/main.rs new file mode 100644 index 000000000..19b2e19fd --- /dev/null +++ b/examples/camera_view/src/main.rs @@ -0,0 +1,414 @@ +use cgmath::point3; +use three_d::*; +use three_d_asset::ProjectionType; + +pub fn main() { + let window = Window::new(WindowSettings { + title: "Camera View!".to_string(), + max_size: Some((1280, 720)), + ..Default::default() + }) + .unwrap(); + let context = window.gl(); + + let mut camera = Camera::new_perspective( + window.viewport(), + vec3(5.0, 2.0, 2.5), + vec3(0.0, 0.0, 0.0), + vec3(0.0, 1.0, 0.0), + degrees(45.0), + 0.1, + 100.0, + ); + let mut control = OrbitControl::new(vec3(0.0, 0.0, 0.0), 1.0, 1000.0); + + let mut debug_camera = Camera::new_orthographic( + window.viewport(), + vec3(10.0, 4.0, 5.0), + vec3(0.0, 0.0, 0.0), + vec3(0.0, 1.0, 0.0), + 24.0, + -1000.0, + 1000.0, + ); + + let mut sphere = Gm::new( + Mesh::new(&context, &CpuMesh::sphere(16)), + PhysicalMaterial::new_transparent( + &context, + &CpuMaterial { + albedo: Srgba { + r: 255, + g: 0, + b: 0, + a: 200, + }, + ..Default::default() + }, + ), + ); + sphere.set_transformation(Mat4::from_translation(vec3(0.0, 1.3, 0.0)) * Mat4::from_scale(0.2)); + let mut cylinder = Gm::new( + Mesh::new(&context, &CpuMesh::cylinder(16)), + PhysicalMaterial::new_transparent( + &context, + &CpuMaterial { + albedo: Srgba { + r: 0, + g: 255, + b: 0, + a: 200, + }, + ..Default::default() + }, + ), + ); + cylinder + .set_transformation(Mat4::from_translation(vec3(1.3, 0.0, 0.0)) * Mat4::from_scale(0.2)); + let mut cube = Gm::new( + Mesh::new(&context, &CpuMesh::cube()), + PhysicalMaterial::new_transparent( + &context, + &CpuMaterial { + albedo: Srgba { + r: 0, + g: 0, + b: 255, + a: 100, + }, + ..Default::default() + }, + ), + ); + cube.set_transformation(Mat4::from_translation(vec3(0.0, 0.0, 1.3)) * Mat4::from_scale(0.2)); + let axes = Axes::new(&context, 0.1, 2.0); + let bounding_box_sphere = Gm::new( + BoundingBox::new(&context, sphere.aabb()), + ColorMaterial { + color: Srgba::BLACK, + ..Default::default() + }, + ); + let bounding_box_cube = Gm::new( + BoundingBox::new(&context, cube.aabb()), + ColorMaterial { + color: Srgba::BLACK, + ..Default::default() + }, + ); + let bounding_box_cylinder = Gm::new( + BoundingBox::new(&context, cylinder.aabb()), + ColorMaterial { + color: Srgba::BLACK, + ..Default::default() + }, + ); + + let light0 = DirectionalLight::new(&context, 1.0, Srgba::WHITE, &vec3(0.0, -0.5, -0.5)); + let light1 = DirectionalLight::new(&context, 1.0, Srgba::WHITE, &vec3(0.0, 0.5, 0.5)); + + // Shapes to represent the main camera view through the debug camera + let mut marker_sphere = CpuMesh::sphere(16); + marker_sphere.transform(&Mat4::from_scale(0.15)).unwrap(); + let mut marker_arrow = CpuMesh::arrow(0.8, 0.6, 16); + marker_arrow + .transform(&Mat4::from_nonuniform_scale(1.0, 0.15, 0.15)) + .unwrap(); + + let mut position_marker = Gm::new( + Mesh::new(&context, &marker_sphere), + PhysicalMaterial::new_opaque( + &context, + &CpuMaterial { + albedo: Srgba::new_opaque(255, 255, 0), + ..Default::default() + }, + ), + ); + let mut target_marker = Gm::new( + Mesh::new(&context, &marker_sphere), + PhysicalMaterial::new_opaque( + &context, + &CpuMaterial { + albedo: Srgba::new_opaque(0, 255, 255), + ..Default::default() + }, + ), + ); + let mut up_marker = Gm::new( + Mesh::new(&context, &marker_arrow), + PhysicalMaterial::new_opaque( + &context, + &CpuMaterial { + albedo: Srgba::GREEN, + ..Default::default() + }, + ), + ); + + let mut marker_vertex = CpuMesh::sphere(16); + marker_vertex.transform(&Mat4::from_scale(0.05)).unwrap(); + let mut marker_edge = CpuMesh::cylinder(16); + marker_edge + .transform(&Mat4::from_nonuniform_scale(1.0, 0.05, 0.05)) + .unwrap(); + + let cube_points = [ + point3(-1.0, -1.0, -1.0), + point3(-1.0, -1.0, 1.0), + point3(-1.0, 1.0, 1.0), + point3(-1.0, 1.0, -1.0), + point3(1.0, 1.0, -1.0), + point3(1.0, 1.0, 1.0), + point3(1.0, -1.0, 1.0), + point3(1.0, -1.0, -1.0), + ]; + let xy_edges = [0, 3, 1, 2, 4, 7, 5, 6, 0, 7, 1, 6, 2, 5, 3, 4]; + let mut frustum_vertex_marker = Gm::new( + InstancedMesh::new(&context, &Instances::default(), &marker_vertex), + PhysicalMaterial::new_opaque( + &context, + &CpuMaterial { + albedo: Srgba::new_opaque(255, 0, 255), + ..Default::default() + }, + ), + ); + let mut frustum_edge_marker = Gm::new( + InstancedMesh::new(&context, &Instances::default(), &marker_edge), + PhysicalMaterial::new_opaque( + &context, + &CpuMaterial { + albedo: Srgba::new_opaque(255, 0, 255), + ..Default::default() + }, + ), + ); + + // Initial properties of the example + let mut camera_ratio = 0.5; + let mut height = 2.0; + let mut fov = if let ProjectionType::Perspective { field_of_view_y } = camera.projection_type() + { + (*field_of_view_y).into() + } else { + degrees(45.0f32) + }; + let mut near_plane = camera.z_near(); + let mut far_plane = camera.z_far(); + + let mut gui = three_d::GUI::new(&context); + window.render_loop(move |mut frame_input| { + // Gui panel to control the number of cubes and whether or not instancing is turned on. + let mut panel_width = 0.0; + let mut camera_changed = false; + gui.update( + &mut frame_input.events, + frame_input.accumulated_time, + frame_input.viewport, + frame_input.device_pixel_ratio, + |gui_context| { + use three_d::egui::*; + SidePanel::left("side_panel").show(gui_context, |ui| { + use three_d::egui::*; + ui.heading("Debug Panel"); + ComboBox::from_label("Camera mode") + .selected_text(match camera.projection_type() { + ProjectionType::Perspective { .. } => "Perspective", + ProjectionType::Orthographic { .. } => "Orthographic", + }) + .show_ui(ui, |ui| { + if ui + .selectable_label( + matches!( + camera.projection_type(), + ProjectionType::Orthographic { .. } + ), + "Orthographic", + ) + .clicked() + { + camera.set_orthographic_projection(height, near_plane, far_plane); + }; + if ui + .selectable_label( + matches!( + camera.projection_type(), + ProjectionType::Perspective { .. } + ), + "Perspective", + ) + .clicked() + { + camera.set_perspective_projection(fov, near_plane, far_plane) + } + }); + camera_changed |= ui + .add(match camera.projection_type() { + ProjectionType::Orthographic { .. } => { + Slider::new(&mut height, 0.0..=120.0).text("Height") + } + _ => Slider::new(&mut fov.0, -120.0..=120.0) + .text("FOV") + .suffix("°"), + }) + .changed(); + camera_changed |= ui + .add(Slider::new(&mut near_plane, -100.0..=100.0).text("Near plane")) + .changed(); + if near_plane >= far_plane { + near_plane = far_plane - 0.1; + } + camera_changed |= ui + .add(Slider::new(&mut far_plane, -100.0..=100.0).text("Far plane")) + .changed(); + if near_plane >= far_plane { + far_plane = near_plane + 0.1; + } + + if camera_changed { + match camera.projection_type() { + ProjectionType::Orthographic { .. } => { + camera.set_orthographic_projection(height, near_plane, far_plane) + } + ProjectionType::Perspective { .. } => { + if near_plane < 0.0 { + near_plane = 0.1; + if far_plane < near_plane { + far_plane = near_plane + 0.1; + } + } + if fov <= degrees(0.0) { + fov = degrees(1.0); + } + camera.set_perspective_projection(fov, near_plane, far_plane) + } + } + } + + ui.add(Label::new( + "Left camera can be changed by the above inputs; right \ + camera shows a debug visual for the left camera. In the \ + debug visual, the yellow sphere is the camera position, \ + the cyan sphere is the camera target, the green arrow \ + is the camera up direction, and the magenta lines \ + outline the camera's view frustum.", + )); + + ui.add( + Slider::new(&mut camera_ratio, 0.01..=0.99) + .text("Main camera to debug camera screen ratio"), + ); + }); + panel_width = gui_context.used_rect().width(); + }, + ); + + let viewport = Viewport { + x: (panel_width * frame_input.device_pixel_ratio) as i32, + y: 0, + width: ((frame_input.viewport.width + - (panel_width * frame_input.device_pixel_ratio) as u32) as f32 + * camera_ratio) as u32, + height: frame_input.viewport.height, + }; + camera.set_viewport(viewport); + + let meta_viewport = Viewport { + x: (panel_width * frame_input.device_pixel_ratio) as i32 + + ((frame_input.viewport.width + - (panel_width * frame_input.device_pixel_ratio) as u32) + as f32 + * camera_ratio) as i32, + y: 0, + width: ((frame_input.viewport.width + - (panel_width * frame_input.device_pixel_ratio) as u32) as f32 + * (1.0 - camera_ratio)) as u32, + height: frame_input.viewport.height, + }; + debug_camera.set_viewport(meta_viewport); + + // Camera control must be after the gui update. + control.handle_events(&mut camera, &mut frame_input.events); + + // Update camera debug shapes + position_marker.set_transformation(Mat4::from_translation(*camera.position())); + target_marker.set_transformation(Mat4::from_translation(*camera.target())); + up_marker.set_transformation( + Mat4::from_translation(*camera.position()) + * Mat4::from_axis_angle( + Vec3::unit_x().cross(*camera.up()), + Vec3::unit_x().angle(*camera.up()), + ), + ); + + let frustum_vertices = cube_points.map(|point| { + (camera.projection() * camera.view()) + .inverse_transform() + .unwrap() + .transform_point(point) + }); + frustum_vertex_marker.set_instances(&Instances { + transformations: frustum_vertices + .into_iter() + .map(|vertex| Mat4::from_translation(vertex.to_vec())) + .collect(), + ..Default::default() + }); + + let frustum_edge_vertices: Vec<_> = frustum_vertices + .iter() + .chain(xy_edges.map(|index| &frustum_vertices[index])) + .collect(); + let frustum_edges = frustum_edge_vertices.chunks_exact(2); + frustum_edge_marker.set_instances(&Instances { + transformations: frustum_edges + .map(|points| { + Mat4::from_translation(points[0].to_vec()) + * Mat4::from_axis_angle( + Vec3::unit_x().cross(points[1] - points[0]).normalize(), + Vec3::unit_x().angle(points[1] - points[0]), + ) + * Mat4::from_nonuniform_scale(points[1].distance(*points[0]), 1.0, 1.0) + }) + .collect(), + ..Default::default() + }); + + let screen = frame_input.screen(); + screen.clear(ClearState::color_and_depth(0.8, 0.8, 0.8, 1.0, 1.0)); + screen.render( + &camera, + sphere + .into_iter() + .chain(&cylinder) + .chain(&cube) + .chain(&axes) + .chain(&bounding_box_sphere) + .chain(&bounding_box_cube) + .chain(&bounding_box_cylinder), + &[&light0, &light1], + ); + screen.render( + &debug_camera, + sphere + .into_iter() + .chain(&cylinder) + .chain(&cube) + .chain(&axes) + .chain(&bounding_box_sphere) + .chain(&bounding_box_cube) + .chain(&bounding_box_cylinder) + .chain(&position_marker) + .chain(&target_marker) + .chain(&up_marker) + .chain(&frustum_vertex_marker) + .chain(&frustum_edge_marker), + &[&light0, &light1], + ); + + screen.write(|| gui.render()).unwrap(); + + FrameOutput::default() + }); +} From 4a25562b86dc1696560012ec773e8500ebb6d7e6 Mon Sep 17 00:00:00 2001 From: thatcomputerguy0101 Date: Thu, 24 Oct 2024 15:09:51 -0400 Subject: [PATCH 2/7] Add missing example dependencies --- examples/camera_view/Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/camera_view/Cargo.toml b/examples/camera_view/Cargo.toml index e85fbf70a..4892f379c 100644 --- a/examples/camera_view/Cargo.toml +++ b/examples/camera_view/Cargo.toml @@ -9,6 +9,8 @@ crate-type = ["cdylib"] [dependencies] three-d = { path = "../../", features=["egui-gui"] } +three-d-asset = {version = "0.7"} +cgmath = "0.18" [target.'cfg(target_arch = "wasm32")'.dependencies] log = "0.4" From 67782f6705c204eab660181ed72873ddc81604a9 Mon Sep 17 00:00:00 2001 From: thatcomputerguy0101 Date: Sat, 26 Oct 2024 00:29:34 -0400 Subject: [PATCH 3/7] Add camera position/view_direction to camera_view example --- examples/camera_view/src/main.rs | 73 +++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/examples/camera_view/src/main.rs b/examples/camera_view/src/main.rs index 19b2e19fd..b56a5892a 100644 --- a/examples/camera_view/src/main.rs +++ b/examples/camera_view/src/main.rs @@ -146,6 +146,27 @@ pub fn main() { ), ); + let mut view_position_marker = Gm::new( + Mesh::new(&context, &marker_sphere), + PhysicalMaterial::new_opaque( + &context, + &CpuMaterial { + albedo: Srgba::new_opaque(255, 127, 0), + ..Default::default() + }, + ), + ); + let mut view_direction_marker = Gm::new( + Mesh::new(&context, &marker_arrow), + PhysicalMaterial::new_opaque( + &context, + &CpuMaterial { + albedo: Srgba::BLUE, + ..Default::default() + }, + ), + ); + let mut marker_vertex = CpuMesh::sphere(16); marker_vertex.transform(&Mat4::from_scale(0.05)).unwrap(); let mut marker_edge = CpuMesh::cylinder(16); @@ -196,6 +217,7 @@ pub fn main() { }; let mut near_plane = camera.z_near(); let mut far_plane = camera.z_far(); + let mut show_click_info = false; let mut gui = three_d::GUI::new(&context); window.render_loop(move |mut frame_input| { @@ -295,6 +317,17 @@ pub fn main() { outline the camera's view frustum.", )); + ui.add(Checkbox::new( + &mut show_click_info, + "Enable position/view_direction debug visuals", + )); + + ui.add(Label::new( + "When enabled, clicking shows the camera base position \ + as an orange sphere and the view direction as a blue \ + arrow.", + )); + ui.add( Slider::new(&mut camera_ratio, 0.01..=0.99) .text("Main camera to debug camera screen ratio"), @@ -375,6 +408,32 @@ pub fn main() { ..Default::default() }); + if show_click_info { + for event in &frame_input.events { + if let Event::MousePress { + button: MouseButton::Left, + handled: false, + position, + .. + } = event + { + view_position_marker.set_transformation(Mat4::from_translation( + camera.position_at_pixel(*position), + )); + let view_direction = camera.view_direction_at_pixel(*position); + view_direction_marker.set_transformation( + Mat4::from_translation(camera.position_at_pixel(*position)) + * Mat4::from_axis_angle( + Vec3::unit_x().cross(view_direction), + Vec3::unit_x().angle(view_direction), + ), + ); + + break; + } + } + } + let screen = frame_input.screen(); screen.clear(ClearState::color_and_depth(0.8, 0.8, 0.8, 1.0, 1.0)); screen.render( @@ -403,7 +462,19 @@ pub fn main() { .chain(&target_marker) .chain(&up_marker) .chain(&frustum_vertex_marker) - .chain(&frustum_edge_marker), + .chain(&frustum_edge_marker) + .chain( + show_click_info + .then_some(&view_position_marker) + .into_iter() + .flatten(), + ) + .chain( + show_click_info + .then_some(&view_direction_marker) + .into_iter() + .flatten(), + ), &[&light0, &light1], ); From b53e5ebd4cd0183deb7db16b1ae7c78854c3f8a6 Mon Sep 17 00:00:00 2001 From: thatcomputerguy0101 Date: Sat, 26 Oct 2024 14:45:27 -0400 Subject: [PATCH 4/7] Simplify reorienting camera markers --- examples/camera_view/src/main.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/examples/camera_view/src/main.rs b/examples/camera_view/src/main.rs index b56a5892a..35e961475 100644 --- a/examples/camera_view/src/main.rs +++ b/examples/camera_view/src/main.rs @@ -369,10 +369,7 @@ pub fn main() { target_marker.set_transformation(Mat4::from_translation(*camera.target())); up_marker.set_transformation( Mat4::from_translation(*camera.position()) - * Mat4::from_axis_angle( - Vec3::unit_x().cross(*camera.up()), - Vec3::unit_x().angle(*camera.up()), - ), + * rotation_matrix_from_dir_to_dir(Vec3::unit_x(), *camera.up()), ); let frustum_vertices = cube_points.map(|point| { @@ -398,10 +395,7 @@ pub fn main() { transformations: frustum_edges .map(|points| { Mat4::from_translation(points[0].to_vec()) - * Mat4::from_axis_angle( - Vec3::unit_x().cross(points[1] - points[0]).normalize(), - Vec3::unit_x().angle(points[1] - points[0]), - ) + * rotation_matrix_from_dir_to_dir(Vec3::unit_x(), points[1] - points[0]) * Mat4::from_nonuniform_scale(points[1].distance(*points[0]), 1.0, 1.0) }) .collect(), @@ -420,12 +414,11 @@ pub fn main() { view_position_marker.set_transformation(Mat4::from_translation( camera.position_at_pixel(*position), )); - let view_direction = camera.view_direction_at_pixel(*position); view_direction_marker.set_transformation( Mat4::from_translation(camera.position_at_pixel(*position)) - * Mat4::from_axis_angle( - Vec3::unit_x().cross(view_direction), - Vec3::unit_x().angle(view_direction), + * rotation_matrix_from_dir_to_dir( + Vec3::unit_x(), + camera.view_direction_at_pixel(*position), ), ); From 7dcd95db466f0bab668d53be47f686c962d52997 Mon Sep 17 00:00:00 2001 From: thatcomputerguy0101 Date: Mon, 28 Oct 2024 13:08:16 -0400 Subject: [PATCH 5/7] Shorten splitscreen slider message --- examples/camera_view/src/main.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/camera_view/src/main.rs b/examples/camera_view/src/main.rs index 35e961475..eff9818c2 100644 --- a/examples/camera_view/src/main.rs +++ b/examples/camera_view/src/main.rs @@ -328,10 +328,7 @@ pub fn main() { arrow.", )); - ui.add( - Slider::new(&mut camera_ratio, 0.01..=0.99) - .text("Main camera to debug camera screen ratio"), - ); + ui.add(Slider::new(&mut camera_ratio, 0.01..=0.99).text("Splitscreen ratio")); }); panel_width = gui_context.used_rect().width(); }, From 4bdd4426e321a734747f6c7b104d5b87dc4bd187 Mon Sep 17 00:00:00 2001 From: thatcomputerguy0101 Date: Mon, 28 Oct 2024 13:11:16 -0400 Subject: [PATCH 6/7] Add planar camera support --- src/renderer/camera.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/renderer/camera.rs b/src/renderer/camera.rs index 4143ef62d..369f02fb2 100644 --- a/src/renderer/camera.rs +++ b/src/renderer/camera.rs @@ -67,6 +67,33 @@ impl Camera { } } + /// + /// New camera which projects the world with a planar projection. + /// + pub fn new_planar( + viewport: Viewport, + position: Vec3, + target: Vec3, + up: Vec3, + field_of_view_y: impl Into, + z_near: f32, + z_far: f32, + ) -> Self { + Self { + camera: three_d_asset::Camera::new_planar( + viewport, + position, + target, + up, + field_of_view_y, + z_near, + z_far, + ), + tone_mapping: ToneMapping::default(), + color_mapping: ColorMapping::default(), + } + } + /// /// Returns an orthographic camera for viewing 2D content. /// The camera is placed at the center of the given viewport. From d6045b0c0d048a0187b73772cec84ba392ff2ab9 Mon Sep 17 00:00:00 2001 From: thatcomputerguy0101 Date: Mon, 28 Oct 2024 13:11:47 -0400 Subject: [PATCH 7/7] Add planar camera to camera_view example --- examples/camera_view/src/main.rs | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/examples/camera_view/src/main.rs b/examples/camera_view/src/main.rs index eff9818c2..2fe6c90aa 100644 --- a/examples/camera_view/src/main.rs +++ b/examples/camera_view/src/main.rs @@ -20,14 +20,14 @@ pub fn main() { 0.1, 100.0, ); - let mut control = OrbitControl::new(vec3(0.0, 0.0, 0.0), 1.0, 1000.0); + let mut control = OrbitControl::new(vec3(0.0, 0.0, 0.0), 0.2, 1000.0); let mut debug_camera = Camera::new_orthographic( window.viewport(), vec3(10.0, 4.0, 5.0), vec3(0.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), - 24.0, + 2.0, -1000.0, 1000.0, ); @@ -238,6 +238,7 @@ pub fn main() { .selected_text(match camera.projection_type() { ProjectionType::Perspective { .. } => "Perspective", ProjectionType::Orthographic { .. } => "Orthographic", + ProjectionType::Planar { .. } => "Planar", }) .show_ui(ui, |ui| { if ui @@ -264,6 +265,18 @@ pub fn main() { { camera.set_perspective_projection(fov, near_plane, far_plane) } + if ui + .selectable_label( + matches!( + camera.projection_type(), + ProjectionType::Planar { .. } + ), + "Planar", + ) + .clicked() + { + camera.set_planar_projection(fov, near_plane, far_plane) + } }); camera_changed |= ui .add(match camera.projection_type() { @@ -305,6 +318,21 @@ pub fn main() { } camera.set_perspective_projection(fov, near_plane, far_plane) } + ProjectionType::Planar { .. } => { + let focal_point = -Angle::cot(fov / 2.0); + if focal_point < 0.0 && near_plane <= focal_point { + near_plane = focal_point + 0.001; + if near_plane > far_plane { + far_plane = near_plane + 0.1; + } + } else if focal_point > 0.0 && far_plane >= focal_point { + far_plane = focal_point - 0.001; + if near_plane > far_plane { + near_plane = far_plane - 0.1; + } + } + camera.set_planar_projection(fov, near_plane, far_plane) + } } }