Create correct primary rays
This commit is contained in:
parent
8f74621937
commit
5db23fca50
5 changed files with 168 additions and 5 deletions
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"rust-analyzer.enableCargoWatchOnStartup": true
|
||||||
|
}
|
BIN
raytrace.png
BIN
raytrace.png
Binary file not shown.
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 5.1 KiB |
63
src/camera.rs
Normal file
63
src/camera.rs
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
use cgmath::{InnerSpace, Vector3};
|
||||||
|
|
||||||
|
use super::ray::Ray;
|
||||||
|
|
||||||
|
pub struct Camera {
|
||||||
|
position: Vector3<f32>,
|
||||||
|
direction: Vector3<f32>,
|
||||||
|
up: Vector3<f32>,
|
||||||
|
right: Vector3<f32>,
|
||||||
|
|
||||||
|
_fov: f32,
|
||||||
|
tan: f32,
|
||||||
|
aspect_ratio: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Camera {
|
||||||
|
pub fn new(
|
||||||
|
eye: Vector3<f32>,
|
||||||
|
center: Vector3<f32>,
|
||||||
|
up: Vector3<f32>,
|
||||||
|
fov: f32,
|
||||||
|
aspect_ratio: f32,
|
||||||
|
) -> Camera {
|
||||||
|
let mut up = up.normalize();
|
||||||
|
|
||||||
|
let view = (center - eye).normalize();
|
||||||
|
|
||||||
|
let right = view.cross(up).normalize();
|
||||||
|
|
||||||
|
up = right.cross(view);
|
||||||
|
|
||||||
|
let fovy = fov.to_radians() / 2.0;
|
||||||
|
|
||||||
|
Camera {
|
||||||
|
position: eye,
|
||||||
|
direction: view,
|
||||||
|
up,
|
||||||
|
right,
|
||||||
|
|
||||||
|
_fov: fovy,
|
||||||
|
tan: fovy.tan(),
|
||||||
|
aspect_ratio,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn primary_ray(&self, x: u32, y: u32, dim_x: u32, dim_y: u32) -> Ray {
|
||||||
|
let x_scaled = Self::scale(x, dim_x);
|
||||||
|
let y_scaled = Self::scale(y, dim_y);
|
||||||
|
|
||||||
|
let mut dir = self.direction;
|
||||||
|
|
||||||
|
dir += self.right * self.tan * self.aspect_ratio * x_scaled;
|
||||||
|
dir += self.up * self.tan * y_scaled;
|
||||||
|
|
||||||
|
dir = dir.normalize();
|
||||||
|
|
||||||
|
Ray::new(self.position, dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scale(v: u32, s: u32) -> f32 {
|
||||||
|
((v as f32 + 0.5) / s as f32) * 2.0 - 1.0
|
||||||
|
}
|
||||||
|
}
|
34
src/main.rs
34
src/main.rs
|
@ -17,6 +17,9 @@ use ray::Ray;
|
||||||
mod view;
|
mod view;
|
||||||
use view::View;
|
use view::View;
|
||||||
|
|
||||||
|
mod camera;
|
||||||
|
use camera::Camera;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let input_data = [
|
let input_data = [
|
||||||
Triangle::new(
|
Triangle::new(
|
||||||
|
@ -48,9 +51,18 @@ fn main() {
|
||||||
fov: 45.0,
|
fov: 45.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
let debug_ray = Ray::primary_ray(640.0, 360.0, 1280.0, 720.0, &view);
|
let camera = Camera::new(
|
||||||
|
vec3(0.0, -4.0, 4.0),
|
||||||
|
vec3(0.0, 0.0, 0.0),
|
||||||
|
vec3(0.0, 0.0, 1.0),
|
||||||
|
45.0,
|
||||||
|
1280.0 / 720.0,
|
||||||
|
);
|
||||||
|
|
||||||
debug_raytracer(1280, 720, &view, &input_data);
|
let _debug_ray = camera.primary_ray(640, 360, 1280, 720);
|
||||||
|
|
||||||
|
//debug_raytracer_view(1280, 720, &view, &input_data);
|
||||||
|
debug_raytracer_camera(1280, 720, &camera, &input_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn f_to_u(color: f32) -> u8 {
|
fn f_to_u(color: f32) -> u8 {
|
||||||
|
@ -111,7 +123,23 @@ fn look_at_test(eye: Vector3<f32>, center: Vector3<f32>, up: Vector3<f32>) -> Ma
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fn debug_raytracer(dim_x: u32, dim_y: u32, view: &View, data: &[Triangle]) {
|
fn debug_raytracer_camera(dim_x: u32, dim_y: u32, camera: &Camera, data: &[Triangle]) {
|
||||||
|
let mut imgbuf = ImageBuffer::new(dim_x, dim_y);
|
||||||
|
|
||||||
|
let acceleration_data = create_acceleration_data(data);
|
||||||
|
|
||||||
|
for (x, y, pixel) in imgbuf.enumerate_pixels_mut() {
|
||||||
|
let ray = camera.primary_ray(x, y, dim_x, dim_y);
|
||||||
|
|
||||||
|
let color = pixel_color(&ray, data, &acceleration_data);
|
||||||
|
|
||||||
|
*pixel = image::Rgb([f_to_u(color.x), f_to_u(color.y), f_to_u(color.z)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
imgbuf.save("raytrace.png").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn debug_raytracer_view(dim_x: u32, dim_y: u32, view: &View, data: &[Triangle]) {
|
||||||
let mut imgbuf = ImageBuffer::new(dim_x, dim_y);
|
let mut imgbuf = ImageBuffer::new(dim_x, dim_y);
|
||||||
|
|
||||||
let acceleration_data = create_acceleration_data(data);
|
let acceleration_data = create_acceleration_data(data);
|
||||||
|
|
73
src/ray.rs
73
src/ray.rs
|
@ -1,7 +1,11 @@
|
||||||
use cgmath::{vec2, vec3, InnerSpace, Vector3};
|
use cgmath::{
|
||||||
|
vec2, vec3, vec4, EuclideanSpace, InnerSpace, Matrix4, Point3, SquareMatrix, Vector2, Vector3,
|
||||||
|
};
|
||||||
|
|
||||||
use super::view::View;
|
use super::view::View;
|
||||||
|
|
||||||
|
use std::f32::consts::PI as M_PI;
|
||||||
|
|
||||||
pub struct Ray {
|
pub struct Ray {
|
||||||
pub origin: Vector3<f32>,
|
pub origin: Vector3<f32>,
|
||||||
pub direction: Vector3<f32>,
|
pub direction: Vector3<f32>,
|
||||||
|
@ -26,6 +30,7 @@ impl Ray {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn primary_ray(x: f32, y: f32, dim_x: f32, dim_y: f32, view: &View) -> Ray {
|
pub fn primary_ray(x: f32, y: f32, dim_x: f32, dim_y: f32, view: &View) -> Ray {
|
||||||
|
/*
|
||||||
let aspect_ratio = dim_x / dim_y;
|
let aspect_ratio = dim_x / dim_y;
|
||||||
|
|
||||||
let uv = vec2((x + 0.5) / dim_x, (y + 0.5) / dim_y);
|
let uv = vec2((x + 0.5) / dim_x, (y + 0.5) / dim_y);
|
||||||
|
@ -41,7 +46,71 @@ impl Ray {
|
||||||
raw_dir.z * aspect_ratio,
|
raw_dir.z * aspect_ratio,
|
||||||
)
|
)
|
||||||
.normalize();
|
.normalize();
|
||||||
|
*/
|
||||||
|
|
||||||
return Self::new(view.position, dir);
|
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();
|
||||||
|
|
||||||
|
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,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue