rustray/src/ray.rs

117 lines
2.9 KiB
Rust
Raw Normal View History

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,
};
}