Starting to work on frustums
This commit is contained in:
parent
66001b2f71
commit
4544acad88
|
@ -1,6 +1,22 @@
|
|||
//! This module contains everything to deal with cameras.
|
||||
|
||||
use math::vector::Vector3;
|
||||
use math::frustum::Frustum;
|
||||
|
||||
/// Multiplies two matrices 4x4
|
||||
fn multiply_matrices(a: [[f32; 4]; 4], b: [[f32; 4]; 4]) -> [[f32; 4]; 4] {
|
||||
let mut res = [[0.0; 4]; 4];
|
||||
|
||||
for i in 0..4 {
|
||||
for j in 0..4 {
|
||||
for k in 0..4 {
|
||||
res[i][j] += a[i][k] + b[k][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
/// The trait that a render camera should implement.
|
||||
///
|
||||
|
@ -11,7 +27,17 @@ pub trait RenderCamera {
|
|||
fn get_view_matrix(&self) -> [[f32; 4]; 4];
|
||||
|
||||
/// Returns the perspective matrix of the camera.
|
||||
fn get_perspective_matrix(&self) -> [[f32; 4]; 4] ;
|
||||
fn get_perspective_matrix(&self) -> [[f32; 4]; 4];
|
||||
|
||||
/// Returns the product of the perspective matrix and the view matrix.
|
||||
fn get_model_view_matrix(&self) -> [[f32; 4]; 4] {
|
||||
multiply_matrices(self.get_perspective_matrix(), self.get_view_matrix())
|
||||
}
|
||||
|
||||
/// Returns the frustum of the camera.
|
||||
fn frustum(&self) -> Frustum {
|
||||
Frustum::from_matrix(&self.get_model_view_matrix())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -226,7 +226,7 @@ impl FirstPersonControls {
|
|||
}
|
||||
|
||||
/// Updates the camera according to the state of the controls.
|
||||
fn update_camera(&self, camera: &mut Camera) {
|
||||
pub fn update_camera(&self, camera: &mut Camera) {
|
||||
camera.position = self.position;
|
||||
camera.target = self.position + self.forward;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
//! Module containing the frustum struct.
|
||||
//!
|
||||
//! The frustum is the field of view of a camera. It allows you to make computation to know what is
|
||||
//! visible or not in an efficient manner, though it doesn't take occlusions into account.
|
||||
|
||||
use math::vector::Vector3;
|
||||
use math::plane::Plane;
|
||||
use math::bounding_box::BoundingBox3;
|
||||
|
||||
/// Struct containing the 6 planes of a 3D camera.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Frustum {
|
||||
/// The planes of the frustum.
|
||||
planes: [Plane; 6],
|
||||
}
|
||||
|
||||
impl Frustum {
|
||||
/// Creates a frustum from the matrix of a camera.
|
||||
///
|
||||
/// This is *ahem...* slightly inspired from THREE.js Frustum
|
||||
pub fn from_matrix(m: &[[f32; 4]; 4]) -> Frustum {
|
||||
|
||||
let m0 = m[0][0]; let m1 = m[0][1]; let m2 = m[0][2]; let m3 = m[0][3];
|
||||
let m4 = m[1][0]; let m5 = m[1][1]; let m6 = m[1][2]; let m7 = m[1][3];
|
||||
let m8 = m[2][0]; let m9 = m[2][1]; let m10 = m[2][2]; let m11 = m[2][3];
|
||||
let m12 = m[3][0]; let m13 = m[3][1]; let m14 = m[3][2]; let m15 = m[3][3];
|
||||
|
||||
Frustum {
|
||||
planes: [
|
||||
Plane::from_coordinates(m3 - m0, m7 - m4, m11 - m8, m15 - m12),
|
||||
Plane::from_coordinates(m3 + m0, m7 + m4, m11 + m8, m15 + m12),
|
||||
Plane::from_coordinates(m3 + m1, m7 + m5, m11 + m9, m15 + m13),
|
||||
Plane::from_coordinates(m3 - m1, m7 - m5, m11 - m9, m15 - m13),
|
||||
Plane::from_coordinates(m3 - m2, m7 - m6, m11 - m10, m15 - m14),
|
||||
Plane::from_coordinates(m3 + m2, m7 + m6, m11 + m10, m15 + m14),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the intersection of the frustum and the bounding box is not empty.
|
||||
pub fn intersects_box(&self, bbox: BoundingBox3<f32>) -> bool {
|
||||
|
||||
use num::Zero;
|
||||
|
||||
let mut p1 = Vector3::<f32>::zero();
|
||||
let mut p2 = Vector3::<f32>::zero();
|
||||
|
||||
for plane in &self.planes {
|
||||
|
||||
p1[0] = if plane.normal().x() > 0.0 { bbox.min().x() } else { bbox.max().x() };
|
||||
p2[0] = if plane.normal().x() > 0.0 { bbox.max().x() } else { bbox.min().x() };
|
||||
p1[1] = if plane.normal().y() > 0.0 { bbox.min().y() } else { bbox.max().y() };
|
||||
p2[1] = if plane.normal().y() > 0.0 { bbox.max().y() } else { bbox.min().y() };
|
||||
p1[2] = if plane.normal().z() > 0.0 { bbox.min().z() } else { bbox.max().z() };
|
||||
p2[2] = if plane.normal().z() > 0.0 { bbox.max().z() } else { bbox.min().z() };
|
||||
|
||||
let d1 = plane.distance_to_point(p1);
|
||||
let d2 = plane.distance_to_point(p2);
|
||||
|
||||
if d1 < 0.0 && d2 < 2.0 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
pub mod vector;
|
||||
pub mod bounding_box;
|
||||
pub mod plane;
|
||||
pub mod frustum;
|
||||
|
||||
use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign};
|
||||
use num::{Zero, One};
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
//! Module containing the plane struct.
|
||||
|
||||
use math::vector::Vector3;
|
||||
|
||||
/// A 3D plane.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Plane {
|
||||
/// The normal of the plane.
|
||||
normal: Vector3<f32>,
|
||||
|
||||
/// The constant, offset of the plane from the origin.
|
||||
constant: f32,
|
||||
}
|
||||
|
||||
impl Plane {
|
||||
/// Creates a new plane from its normal and its constant.
|
||||
pub fn from_coordinates(a: f32, b: f32, c: f32, w: f32) -> Plane {
|
||||
let mut p = Plane {
|
||||
normal: Vector3::new(a, b, c),
|
||||
constant: w,
|
||||
};
|
||||
p.normalize();
|
||||
p
|
||||
}
|
||||
|
||||
/// Creates a new plane from its normal and its constant.
|
||||
pub fn from_normal_and_constant(normal: Vector3<f32>, constant: f32) -> Plane {
|
||||
Plane::from_coordinates(normal.x(), normal.y(), normal.z(), constant)
|
||||
}
|
||||
|
||||
/// Creates a new plane from its normal and a point of the plane.
|
||||
pub fn from_normal_and_point(normal: Vector3<f32>, point: Vector3<f32>) -> Plane {
|
||||
Plane::from_normal_and_constant(normal, - point.dot(normal))
|
||||
}
|
||||
|
||||
|
||||
/// Creates a new plane from three points.
|
||||
pub fn from_points(p1: Vector3<f32>, p2: Vector3<f32>, p3: Vector3<f32>) -> Plane {
|
||||
let p1p2 = p2 - p1;
|
||||
let p1p3 = p3 - p1;
|
||||
Plane::from_normal_and_point(p1p2.cross_product(p1p3), p1)
|
||||
}
|
||||
|
||||
/// Normalizes the plane.
|
||||
pub fn normalize(&mut self) {
|
||||
let normal_inverse = 1.0 / self.normal.norm();
|
||||
self.normal *= normal_inverse;
|
||||
self.constant *= normal_inverse;
|
||||
}
|
||||
|
||||
/// Returns the normal of the plane.
|
||||
pub fn normal(&self) -> Vector3<f32> {
|
||||
self.normal
|
||||
}
|
||||
|
||||
/// Returns the constant of the plane.
|
||||
pub fn constant(&self) -> f32 {
|
||||
self.constant
|
||||
}
|
||||
|
||||
/// Returns the distance between the plane and the point.
|
||||
pub fn distance_to_point(&self, point: Vector3<f32>) -> f32 {
|
||||
self.normal.dot(point) + self.constant
|
||||
}
|
||||
}
|
|
@ -4,6 +4,8 @@ use std::cell::Ref;
|
|||
use std::borrow::Cow;
|
||||
|
||||
use image;
|
||||
use image::{ImageBuffer, Rgba};
|
||||
|
||||
use glium::texture::{RawImage2d, SrgbTexture2d, Texture2dDataSink};
|
||||
use glium::{Frame, Display, Surface, Program, DrawParameters, Depth, VertexBuffer};
|
||||
use glium::{Rect, BlitTarget};
|
||||
|
@ -88,9 +90,14 @@ impl Renderer {
|
|||
/// Creates a SrgbTexture from a path to an image.
|
||||
pub fn make_texture(&self, path: &str) -> SrgbTexture2d {
|
||||
let image = image::open(path).unwrap().to_rgba();
|
||||
let dimensions = image.dimensions();
|
||||
let image = RawImage2d::from_raw_rgba_reversed(&image.into_raw(), dimensions);
|
||||
SrgbTexture2d::new(&self.display, image).ok().unwrap()
|
||||
self.make_texture_from_buffer(image)
|
||||
}
|
||||
|
||||
/// Creates a SrgbTexture from an image buffer.
|
||||
pub fn make_texture_from_buffer(&self, buffer: ImageBuffer<Rgba<u8>, Vec<u8>>) -> SrgbTexture2d {
|
||||
let dimensions = buffer.dimensions();
|
||||
let buffer = RawImage2d::from_raw_rgba_reversed(&buffer.into_raw(), dimensions);
|
||||
SrgbTexture2d::new(&self.display, buffer).ok().unwrap()
|
||||
}
|
||||
|
||||
/// Creates a 1x1 SrgbTexture with the color passed as parameter.
|
||||
|
|
20
src/scene.rs
20
src/scene.rs
|
@ -2,13 +2,13 @@
|
|||
|
||||
use std::slice::{Iter, IterMut};
|
||||
use std::vec::IntoIter;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::cell::RefCell;
|
||||
use model::Model;
|
||||
|
||||
/// Represents a 3D scene with models.
|
||||
pub struct Scene {
|
||||
models: Vec<Rc<RefCell<Model>>>,
|
||||
models: Vec<Arc<RefCell<Model>>>,
|
||||
}
|
||||
|
||||
impl Scene {
|
||||
|
@ -20,29 +20,29 @@ impl Scene {
|
|||
}
|
||||
|
||||
/// Adds a model to the scene.
|
||||
pub fn push(&mut self, model: Rc<RefCell<Model>>) {
|
||||
pub fn push(&mut self, model: Arc<RefCell<Model>>) {
|
||||
self.models.push(model);
|
||||
}
|
||||
|
||||
/// Converts the model to a Rc<RefCell<Model>> and adds it to the scene.
|
||||
/// Converts the model to a Arc<RefCell<Model>> and adds it to the scene.
|
||||
pub fn emplace(&mut self, model: Model) {
|
||||
self.models.push(Rc::new(RefCell::new(model)));
|
||||
self.models.push(Arc::new(RefCell::new(model)));
|
||||
}
|
||||
|
||||
/// Returns an iterator to the models of the scene.
|
||||
pub fn iter(&self) -> Iter<Rc<RefCell<Model>>> {
|
||||
pub fn iter(&self) -> Iter<Arc<RefCell<Model>>> {
|
||||
self.models.iter()
|
||||
}
|
||||
|
||||
/// Returns a mutable iterator to the model of the scene.
|
||||
pub fn iter_mut(&mut self) -> IterMut<Rc<RefCell<Model>>> {
|
||||
pub fn iter_mut(&mut self) -> IterMut<Arc<RefCell<Model>>> {
|
||||
self.models.iter_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for Scene {
|
||||
type IntoIter = IntoIter<Rc<RefCell<Model>>>;
|
||||
type Item = Rc<RefCell<Model>>;
|
||||
type IntoIter = IntoIter<Arc<RefCell<Model>>>;
|
||||
type Item = Arc<RefCell<Model>>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.models.into_iter()
|
||||
|
@ -52,7 +52,7 @@ impl IntoIterator for Scene {
|
|||
impl From<Vec<Model>> for Scene {
|
||||
fn from(input: Vec<Model>) -> Scene {
|
||||
Scene {
|
||||
models: input.into_iter().map(|x| Rc::new(RefCell::new(x))).collect(),
|
||||
models: input.into_iter().map(|x| Arc::new(RefCell::new(x))).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue