2019-03-21 06:40:30 +00:00
|
|
|
use cgmath::{
|
|
|
|
vec2, vec3, vec4, EuclideanSpace, InnerSpace, Matrix4, Point3, SquareMatrix, Vector2, Vector3,
|
|
|
|
};
|
2019-03-20 14:56:29 +00:00
|
|
|
|
|
|
|
use super::view::View;
|
|
|
|
|
2019-03-21 06:40:30 +00:00
|
|
|
use std::f32::consts::PI as M_PI;
|
|
|
|
|
2019-03-20 14:56:29 +00:00
|
|
|
pub struct Ray {
|
|
|
|
pub origin: Vector3<f32>,
|
|
|
|
pub direction: Vector3<f32>,
|
|
|
|
pub inv_direction: Vector3<f32>,
|
|
|
|
pub signs: Vector3<usize>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Ray {
|
|
|
|
pub fn new(origin: Vector3<f32>, direction: Vector3<f32>) -> Ray {
|
|
|
|
let inv_direction = 1.0 / direction;
|
|
|
|
|
|
|
|
let x = (inv_direction.x < 0.0) as usize;
|
|
|
|
let y = (inv_direction.y < 0.0) as usize;
|
|
|
|
let z = (inv_direction.z < 0.0) as usize;
|
|
|
|
|
|
|
|
Ray {
|
|
|
|
origin,
|
|
|
|
direction,
|
|
|
|
inv_direction,
|
|
|
|
signs: Vector3::new(x, y, z),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-20 16:15:07 +00:00
|
|
|
pub fn primary_ray(x: f32, y: f32, dim_x: f32, dim_y: f32, view: &View) -> Ray {
|
2019-03-21 06:40:30 +00:00
|
|
|
/*
|
2019-03-20 16:15:07 +00:00
|
|
|
let aspect_ratio = dim_x / dim_y;
|
2019-03-20 14:56:29 +00:00
|
|
|
|
2019-03-20 16:15:07 +00:00
|
|
|
let uv = vec2((x + 0.5) / dim_x, (y + 0.5) / dim_y);
|
2019-03-20 14:56:29 +00:00
|
|
|
|
|
|
|
let (up, right) = view.axises();
|
|
|
|
|
|
|
|
let trans = 2.0 * uv - vec2(1.0, 1.0);
|
2019-03-20 16:15:07 +00:00
|
|
|
let raw_dir = view.look_at + right * trans.x + up * trans.y;
|
2019-03-20 14:56:29 +00:00
|
|
|
|
2019-03-20 16:15:07 +00:00
|
|
|
let dir = vec3(
|
|
|
|
raw_dir.x * aspect_ratio,
|
|
|
|
raw_dir.y,
|
|
|
|
raw_dir.z * aspect_ratio,
|
|
|
|
)
|
|
|
|
.normalize();
|
2019-03-21 06:40:30 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
let aspect_ratio = dim_x / dim_y;
|
|
|
|
let fov = view.fov / M_PI * 2.0 / 180.0;
|
|
|
|
|
|
|
|
let p_x = (1.0 - 2.0 * ((x as f32 + 0.5) / dim_x as f32)) * fov * aspect_ratio;
|
|
|
|
let p_y = (2.0 * (((y) as f32 + 0.5) / dim_y as f32) - 1.0) * fov;
|
|
|
|
|
|
|
|
return Self::cast_ray(vec2(p_x, p_y), view);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn cast_ray(uv: Vector2<f32>, view: &View) -> Ray {
|
|
|
|
let look_at = Matrix4::look_at(
|
|
|
|
Point3::from_vec(view.position),
|
|
|
|
Point3::from_vec(view.look_at),
|
|
|
|
vec3(0.0, 0.0, 1.0),
|
|
|
|
);
|
|
|
|
|
|
|
|
let camera_to_world = look_at.invert().unwrap();
|
2019-03-20 16:15:07 +00:00
|
|
|
|
2019-03-21 06:40:30 +00:00
|
|
|
let origin = camera_to_world * vec4(0.0, 0.0, 0.0, 1.0);
|
|
|
|
let direction = camera_to_world * vec4(uv.x, uv.y, -1.0, 1.0);
|
|
|
|
|
|
|
|
Ray::new(origin.truncate(), -direction.truncate().normalize())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn perspective(fov_y: f32, aspect: f32, z_near: f32, z_far: f32) -> cgmath::Matrix4<f32> {
|
|
|
|
let zero = 0.0;
|
|
|
|
let one = 1.0;
|
|
|
|
let two = 2.0;
|
|
|
|
let q = one / (fov_y / two).tan();
|
|
|
|
let a = q / aspect;
|
|
|
|
let b = (z_near + z_far) / (z_near - z_far);
|
|
|
|
let c = (two * z_near * z_far) / (z_near - z_far);
|
|
|
|
|
|
|
|
cgmath::Matrix4::new(
|
|
|
|
a,
|
|
|
|
zero,
|
|
|
|
zero,
|
|
|
|
zero,
|
|
|
|
zero,
|
|
|
|
-q,
|
|
|
|
zero,
|
|
|
|
zero,
|
|
|
|
zero,
|
|
|
|
zero,
|
|
|
|
b,
|
|
|
|
zero - one,
|
|
|
|
zero,
|
|
|
|
zero,
|
|
|
|
c,
|
|
|
|
zero,
|
|
|
|
)
|
2019-03-20 14:56:29 +00:00
|
|
|
}
|
|
|
|
}
|
2019-03-21 06:40:30 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn text_ray_casting() {
|
|
|
|
let center = vec3(0.0, 0.0, 0.0);
|
|
|
|
|
|
|
|
let view = View {
|
|
|
|
position: vec3(0.0, -4.0, 4.0),
|
|
|
|
look_at: center,
|
|
|
|
up: vec3(0.0, 0.0, 1.0),
|
|
|
|
fov: 45.0,
|
|
|
|
};
|
|
|
|
}
|