Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add orthographic and infinite perspective cameras #22

Merged
merged 5 commits into from
Feb 22, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions src/controls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ impl OrbitControls {
self.pan_up(distance);
} else {
// TODO!: orthographic camera pan
unimplemented!("orthographic camera pan")
warn!("unimplemented: orthographic camera pan")
}
}

Expand All @@ -225,14 +225,14 @@ impl OrbitControls {
// Processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis
pub fn process_mouse_scroll(&mut self, mut yoffset: f32) {
yoffset *= ZOOM_SENSITIVITY;
if self.camera.fovy >= MIN_ZOOM && self.camera.fovy <= MAZ_ZOOM {
self.camera.fovy -= yoffset;
if self.camera.fovy.0 >= MIN_ZOOM && self.camera.fovy.0 <= MAZ_ZOOM {
self.camera.fovy.0 -= yoffset;
}
if self.camera.fovy <= MIN_ZOOM {
self.camera.fovy = MIN_ZOOM;
if self.camera.fovy.0 <= MIN_ZOOM {
self.camera.fovy.0 = MIN_ZOOM;
}
if self.camera.fovy >= MAZ_ZOOM {
self.camera.fovy = MAZ_ZOOM;
if self.camera.fovy.0 >= MAZ_ZOOM {
self.camera.fovy.0 = MAZ_ZOOM;
}
self.camera.update_projection_matrix();
}
Expand Down
4 changes: 2 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// #![feature(test)]
#[macro_use] extern crate clap;
extern crate cgmath;
// use cgmath::prelude::*;
use cgmath::Deg;

extern crate collision;

Expand Down Expand Up @@ -121,7 +121,7 @@ pub fn main() {
index: args.value_of("CAM-INDEX").map(|n| n.parse().unwrap()).unwrap(),
position: args.value_of("CAM-POS").map(|v| parse_vec3(v).unwrap()),
target: args.value_of("CAM-TARGET").map(|v| parse_vec3(v).unwrap()),
fovy: args.value_of("CAM-FOVY").map(|n| n.parse().unwrap()).unwrap(),
fovy: args.value_of("CAM-FOVY").map(|n| Deg(n.parse().unwrap())).unwrap(),
};

let log_level = match args.occurrences_of("verbose") {
Expand Down
57 changes: 48 additions & 9 deletions src/render/camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@ use ::controls::{ZOOM};

#[derive(Clone)]
pub struct Camera {
pub index: usize, // gltf index
pub name: Option<String>,

pub projection_matrix: Matrix4,

pub znear: f32,
pub zfar: Option<f32>,

// perspective camera
// TODO!: setters that update...
pub fovy: f32, // degrees
pub fovy: Deg<f32>,
aspect_ratio: f32,

// orthographic camera
Expand All @@ -26,10 +29,13 @@ pub struct Camera {
impl Default for Camera {
fn default() -> Self {
Camera {
index: 0,
name: None,

znear: 0.01,
zfar: Some(1000.0),

fovy: ZOOM,
fovy: Deg(ZOOM),
aspect_ratio: 1.0,

xmag: None,
Expand All @@ -43,10 +49,12 @@ impl Default for Camera {
impl Camera {
pub fn from_gltf(g_camera: &gltf::Camera) -> Self {
let mut camera = Camera {
index: g_camera.index(),
name: g_camera.name().map(|n| n.to_owned()),
projection_matrix: Matrix4::zero(),
znear: 0.0,
zfar: None,
fovy: 0.0,
fovy: Deg(0.0),
aspect_ratio: 1.0,
xmag: None,
ymag: None,
Expand All @@ -55,7 +63,7 @@ impl Camera {
Projection::Perspective(persp) => {
// TODO!!: ignoring aspect ratio for now as it would require window resizing...
let _aspect = persp.aspect_ratio();
camera.fovy = Deg::from(Rad(persp.yfov())).0;
camera.fovy = Deg::from(Rad(persp.yfov()));
camera.znear = persp.znear();
camera.zfar = persp.zfar();
},
Expand All @@ -80,20 +88,51 @@ impl Camera {
}

pub fn update_projection_matrix(&mut self) {
if let Some(_xmag) = self.xmag {
unimplemented!("orthographic camera") // TODO!!!: ortho camera
if let Some(xmag) = self.xmag {
// from https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#orthographic-projection
let r = xmag;
let t = self.ymag.unwrap();
let f = self.zfar.unwrap();
let n = self.znear;
self.projection_matrix = Matrix4::new(
1.0/r, 0.0, 0.0, 0.0, // NOTE: first column!
0.0, 1.0/t, 0.0, 0.0, // 2nd
0.0, 0.0, 2.0/(n-f), 0.0, // 3rd
0.0, 0.0, (f+n)/(n-f), 1.0 // 4th
);
} else if let Some(zfar) = self.zfar {
self.projection_matrix = perspective(
Deg(self.fovy),
self.fovy,
self.aspect_ratio,
self.znear, zfar)
} else {
// TODO!!: inifinite perspective (missing sample models)
unimplemented!("infinite perspective")
// from https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#infinite-perspective-projection
let a = self.aspect_ratio;
let y = Rad::from(self.fovy).0;
let n = self.znear;

self.projection_matrix = Matrix4::new(
1.0/(a*(0.5*y).tan()), 0.0, 0.0, 0.0, // NOTE: first column!
0.0, 1.0/(0.5*y).tan(), 0.0, 0.0,
0.0, 0.0, -1.0, -1.0,
0.0, 0.0, -2.0*n, 0.0
);
}
}

pub fn is_perspective(&self) -> bool {
self.xmag.is_none()
}

pub fn description(&self) -> String {
let type_ = if !self.is_perspective() {
"ortho"
} else if self.zfar.is_none() {
"infinite perspective"
} else {
"perspective"
};

format!("{} ({:?}, {})", self.index, self.name, type_)
}
}
1 change: 0 additions & 1 deletion src/render/scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ impl Scene {
let node = root.unsafe_get_node_mut(*node_id);
node.update_transform(root, &root_transform);
node.update_bounds(root);
// TODO!: visualize final bounds
scene.bounds = scene.bounds.union(&node.bounds);
}

Expand Down
1 change: 0 additions & 1 deletion src/shader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@ bitflags! {
const HAS_NORMALS = 1;
const HAS_TANGENTS = 1 << 1;
const HAS_UV = 1 << 2;
// TODO!: the shader doesn't have colors yet
const HAS_COLORS = 1 << 3;

// fragment shader only
Expand Down
53 changes: 29 additions & 24 deletions src/viewer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::path::Path;
use std::process;
use std::time::Instant;

use cgmath::{ Point3 };
use cgmath::{ Deg, Point3 };
use collision::Aabb;
use gl;
use glutin;
Expand Down Expand Up @@ -44,7 +44,7 @@ pub struct CameraOptions {
pub index: i32,
pub position: Option<Vector3>,
pub target: Option<Vector3>,
pub fovy: f32,
pub fovy: Deg<f32>,
}

pub struct GltfViewer {
Expand Down Expand Up @@ -169,22 +169,24 @@ impl GltfViewer {
};
unsafe { gl_check_error!(); };

if !viewer.root.camera_nodes.is_empty() && !camera_options.index == -1 {
if camera_options.index >= viewer.root.camera_nodes.len() as i32 {
error!("No camera with index {} found in glTF file (max: {})",
camera_options.index, viewer.root.camera_nodes.len() - 1);
process::exit(2)
}
if camera_options.index != 0 && camera_options.index >= viewer.root.camera_nodes.len() as i32 {
error!("No camera with index {} found in glTF file (max: {})",
camera_options.index, viewer.root.camera_nodes.len() as i32 - 1);
process::exit(2)
}
if !viewer.root.camera_nodes.is_empty() && camera_options.index != -1 {
let cam_node = &viewer.root.get_camera_node(camera_options.index as usize);
viewer.orbit_controls.set_camera(
cam_node.camera.as_ref().unwrap(),
&cam_node.final_transform);
let cam_node_info = format!("{} ({:?})", cam_node.index, cam_node.name);
let cam = cam_node.camera.as_ref().unwrap();
info!("Using camera {} on node {}", cam.description(), cam_node_info);
viewer.orbit_controls.set_camera(cam, &cam_node.final_transform);

if camera_options.position.is_some() || camera_options.target.is_some() {
warn!("Ignoring --cam-pos / --cam-target since --cam-index is given.")
}
} else {
viewer.set_camera_from_bounds();
info!("Determining camera view from bounding box");
viewer.set_camera_from_bounds(false);

if let Some(p) = camera_options.position {
viewer.orbit_controls.position = Point3::from_vec(p)
Expand Down Expand Up @@ -239,25 +241,28 @@ impl GltfViewer {
}

/// determine "nice" camera perspective from bounding box. Inspired by donmccurdy/three-gltf-viewer
fn set_camera_from_bounds(&mut self) {
fn set_camera_from_bounds(&mut self, straight: bool) {
let bounds = &self.scene.bounds;
let size = (bounds.max - bounds.min).magnitude();
let center = bounds.center();

let _max_distance = size * 10.0;
// TODO: x,y addition optional, z optionally minus instead
let cam_pos = Point3::new(
center.x + size / 2.0,
center.y + size / 5.0,
center.z + size / 2.0,
);
let _near = size / 100.0;
let _far = size * 100.0;
// TODO: x,y addition optional
let cam_pos = if straight {
Point3::new(
center.x,
center.y,
center.z + size * 0.75,
)
} else {
Point3::new(
center.x + size / 2.0,
center.y + size / 5.0,
center.z + size / 2.0,
)
};

self.orbit_controls.position = cam_pos;
self.orbit_controls.target = center;

// TODO!: set near, far, max_distance, obj_pos_modifier...
}

pub fn start_render_loop(&mut self) {
Expand Down