middle of attempting to fix rotations
This commit is contained in:
parent
6cbd93aad0
commit
8657806aba
10 changed files with 692 additions and 78 deletions
122
src/geometry.rs
122
src/geometry.rs
|
|
@ -1,87 +1,69 @@
|
|||
use cgmath::{Angle, InnerSpace, Matrix4, SquareMatrix, Vector3, Vector4};
|
||||
use easy_gltf::{Camera, Projection};
|
||||
use cgmath::{InnerSpace, Vector3};
|
||||
use cgmath::num_traits::abs;
|
||||
use easy_gltf::model::Triangle;
|
||||
use crate::ray::Ray;
|
||||
|
||||
pub struct Ray {
|
||||
source: Vector3<f32>,
|
||||
direction: Vector3<f32>,
|
||||
}
|
||||
const EPSILON: f32 = 0.000001;
|
||||
|
||||
pub trait Intersectable {
|
||||
/*
|
||||
tests whether the ray intersects the Intersectable.
|
||||
returns: The intersection point or empty if there is none
|
||||
*/
|
||||
fn test_isec(&self, ray: &Ray) -> Option<Vector3<f32>>;
|
||||
fn test_isec(&self, ray: &Ray) -> Option<(f32, Vector3<f32>)>;
|
||||
}
|
||||
|
||||
impl Intersectable for Triangle {
|
||||
//perform muller trumbore intersection
|
||||
fn test_isec(&self, ray: &Ray) -> Option<Vector3<f32>> {
|
||||
//TODO: implement correct intersection here
|
||||
if ray.direction.x > 0.5 &&
|
||||
ray.direction.x < 0.6 &&
|
||||
ray.direction.y > 0.1 &&
|
||||
ray.direction.y < 0.6 {
|
||||
return Some(Vector3::new(1.0, 1.0, 1.0));
|
||||
fn test_isec(&self, ray: &Ray) -> Option<(f32, Vector3<f32>)> {
|
||||
assert!(
|
||||
abs(ray.direction.dot(ray.direction) - 1.0) < EPSILON,
|
||||
"Ray direction not normalized"
|
||||
);
|
||||
|
||||
//get triangle vertices
|
||||
let p0 = self[0].position;
|
||||
let p1 = self[1].position;
|
||||
let p2 = self[2].position;
|
||||
|
||||
let edge1 = p1 - p0;
|
||||
let edge2 = p2 - p0;
|
||||
|
||||
let ray_cross_e2 = ray.direction.cross(edge2);
|
||||
let determinant = edge1.dot(ray_cross_e2);
|
||||
|
||||
//ray is parallel to triangle
|
||||
if determinant > -EPSILON && determinant < EPSILON {
|
||||
return None;
|
||||
}
|
||||
|
||||
let inverse_determinant = 1.0 / determinant;
|
||||
|
||||
let s = ray.source - p0;
|
||||
let u = s.dot(ray_cross_e2) * inverse_determinant;
|
||||
|
||||
//early out 2
|
||||
if u < 0.0 || u > 1.0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let s_cross_e1 = s.cross(edge1);
|
||||
let v = ray.direction.dot(s_cross_e1) * inverse_determinant;
|
||||
|
||||
//early out 3
|
||||
if v < 0.0 || u + v > 1.0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
//compute ray parameter t
|
||||
|
||||
let t = edge2.dot(s_cross_e1) * inverse_determinant;
|
||||
|
||||
if t > EPSILON {
|
||||
return Option::from((t, ray.source + ray.direction * t));
|
||||
}
|
||||
// This means that there is a line intersection but not a ray intersection.
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn construct_primary_rays(camera: &Camera,
|
||||
(width, height): (usize, usize),
|
||||
(pixel_x_coord, pixel_y_coord): (usize, usize),
|
||||
) -> Vec<Ray> {
|
||||
//only allow perspective rendering
|
||||
//TODO: ignoring aspect ratio here
|
||||
let fovy = match camera.projection {
|
||||
Projection::Perspective { yfov, aspect_ratio: _aspect_ratio } => { yfov }
|
||||
Projection::Orthographic { .. } => { panic!("Orthographic rendering not supported.") }
|
||||
};
|
||||
|
||||
//ray origin in world space
|
||||
let origin_world_space = camera.position();
|
||||
|
||||
//seems to be the distance from the camera origin to the view plane
|
||||
let z: f32 = height as f32 / fovy.tan();
|
||||
|
||||
//obtain the inverse transformation Matrix
|
||||
let inverse_transform = camera.transform.invert().unwrap_or_else(||
|
||||
panic!("Non invertible transform Matrix. giving up.")
|
||||
);
|
||||
|
||||
//TODO: take ray multiplier per pixel into account here
|
||||
let mut rays: Vec<Ray> = Vec::with_capacity(height * width);
|
||||
|
||||
//generate all rays for this pixel and add them to the rays vector
|
||||
//TODO: use blue noise here to generate multiple rays per pixel
|
||||
rays.push(generate_ray(
|
||||
width,
|
||||
height,
|
||||
&inverse_transform,
|
||||
z,
|
||||
pixel_x_coord,
|
||||
pixel_y_coord,
|
||||
origin_world_space));
|
||||
|
||||
rays
|
||||
}
|
||||
|
||||
fn generate_ray(image_width: usize,
|
||||
image_height: usize,
|
||||
inverse_transform: &Matrix4<f32>,
|
||||
focal_length: f32,
|
||||
u: usize,
|
||||
v: usize,
|
||||
ray_origin: Vector3<f32>) -> Ray {
|
||||
//calculate the ray direction and translate it to world space
|
||||
let direction_view_space: Vector4<f32> =
|
||||
Vector4::new(u as f32 - (image_width as f32 / 2.0),
|
||||
v as f32 - (image_height as f32 / 2.0),
|
||||
-focal_length,
|
||||
0.0);
|
||||
let direction_world_space = inverse_transform * direction_view_space;
|
||||
|
||||
Ray { source: ray_origin, direction: direction_world_space.normalize().truncate() }
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
mod renderer;
|
||||
mod geometry;
|
||||
mod ray;
|
||||
|
||||
use std::string::String;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
|
|
|||
69
src/ray.rs
Normal file
69
src/ray.rs
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
use std::ops::Mul;
|
||||
use cgmath::{Angle, InnerSpace, Matrix4, SquareMatrix, Vector3, Vector4};
|
||||
use easy_gltf::{Camera, Projection};
|
||||
|
||||
pub struct Ray {
|
||||
pub(crate) source: Vector3<f32>,
|
||||
pub(crate) direction: Vector3<f32>,
|
||||
}
|
||||
|
||||
pub fn construct_primary_rays(camera: &Camera,
|
||||
(width, height): (usize, usize),
|
||||
(pixel_x_coord, pixel_y_coord): (usize, usize),
|
||||
) -> Vec<Ray> {
|
||||
//only allow perspective rendering
|
||||
//TODO: ignoring aspect ratio here
|
||||
let (fovy, aspect_ratio) = match camera.projection {
|
||||
Projection::Perspective { yfov, aspect_ratio } => {
|
||||
(yfov, aspect_ratio) }
|
||||
Projection::Orthographic { .. } => { panic!("Orthographic rendering not supported.") }
|
||||
};
|
||||
|
||||
//ray origin in world space
|
||||
let origin_world_space = camera.position();
|
||||
//dbg!(camera.transform);
|
||||
|
||||
// the distance from the camera origin to the view plane
|
||||
let z: f32 = height as f32 / (2.0 * fovy.mul(0.5).tan());
|
||||
|
||||
//obtain the inverse transformation Matrix
|
||||
let inverse_transform = camera.transform.invert().unwrap_or_else(||
|
||||
panic!("Non invertible transform Matrix. giving up.")
|
||||
);
|
||||
|
||||
//TODO: take ray multiplier per pixel into account here
|
||||
let mut rays: Vec<Ray> = Vec::with_capacity(height * width);
|
||||
|
||||
//generate all rays for this pixel and add them to the rays vector
|
||||
//TODO: use blue noise here to generate multiple rays per pixel
|
||||
rays.push(generate_single_primary_ray(
|
||||
width,
|
||||
height,
|
||||
&inverse_transform,
|
||||
z,
|
||||
pixel_x_coord,
|
||||
pixel_y_coord,
|
||||
origin_world_space));
|
||||
|
||||
rays
|
||||
}
|
||||
|
||||
fn generate_single_primary_ray(image_width: usize,
|
||||
image_height: usize,
|
||||
inverse_transform: &Matrix4<f32>,
|
||||
focal_length: f32,
|
||||
u: usize,
|
||||
v: usize,
|
||||
ray_origin: Vector3<f32>) -> Ray {
|
||||
//calculate the ray direction and translate it to world space
|
||||
let direction_view_space: Vector4<f32> =
|
||||
Vector4::new(u as f32 - (image_width as f32 / 2.0),
|
||||
v as f32 - (image_height as f32 / 2.0),
|
||||
-focal_length,
|
||||
0.0);
|
||||
//TODO: Rotation is fucked
|
||||
//x rotation has sign wrong, y and z are flipped
|
||||
let direction_world_space = inverse_transform * direction_view_space.normalize();
|
||||
|
||||
Ray { source: ray_origin, direction: direction_world_space.truncate().normalize() }
|
||||
}
|
||||
|
|
@ -1,11 +1,13 @@
|
|||
use std::cmp::max;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use cgmath::{Vector2, Vector3, Vector4, Zero};
|
||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||
use easy_gltf::model::{Mode};
|
||||
use easy_gltf::{Camera, Scene};
|
||||
use image::{DynamicImage, GenericImage, Rgba};
|
||||
use crate::Args;
|
||||
use crate::geometry::{construct_primary_rays, Intersectable, Ray};
|
||||
|
||||
use crate::geometry::{Intersectable};
|
||||
use crate::ray::{construct_primary_rays, Ray};
|
||||
|
||||
pub fn render(scenes: &Vec<Scene>,
|
||||
cl_args: &Args,
|
||||
|
|
@ -23,8 +25,8 @@ pub fn render(scenes: &Vec<Scene>,
|
|||
(px, py),
|
||||
);
|
||||
|
||||
//let the initial pixel color be white and opaque
|
||||
let mut pixel_color: Rgba<u8> = Rgba([0, 0, 0, 255]);
|
||||
//let the initial pixel color be black and transparent
|
||||
let mut pixel_color: Rgba<u8> = Rgba::from([0, 0, 0, 255]);
|
||||
|
||||
//cast each ray and get the output color
|
||||
//TODO: in the end we will want to average the colors out here
|
||||
|
|
@ -45,7 +47,12 @@ pub fn render(scenes: &Vec<Scene>,
|
|||
|
||||
|
||||
fn raytrace(ray: &Ray, scene: &Scene) -> Rgba<u8> {
|
||||
let mut pixel_color: Rgba<u8> = Rgba([0, 0, 0, 255]);
|
||||
let mut pixel_color: Rgba<u8> = Rgba::from([0, 0, 0, 255]);
|
||||
|
||||
|
||||
let mut smallest_t: f32 = f32::MAX;
|
||||
let mut clostest_intersection_point: Option<Vector3<f32>> = None;
|
||||
let mut color_at_isec = [0, 0, 0, 0];
|
||||
|
||||
//test intersection with all models in the scene
|
||||
//TODO: Improve, to avoid iterating all models
|
||||
|
|
@ -64,12 +71,29 @@ fn raytrace(ray: &Ray, scene: &Scene) -> Rgba<u8> {
|
|||
match triangle.test_isec(&ray) {
|
||||
//boilerplate implementation to set pixel to red if any intersection happened
|
||||
None => {}
|
||||
Some(point) => {
|
||||
pixel_color.0 = [255, 255, 255, 255];
|
||||
return
|
||||
Some((t, isec)) => {
|
||||
// a new closer Point is found
|
||||
if t < smallest_t {
|
||||
smallest_t = t;
|
||||
clostest_intersection_point = Option::from(isec);
|
||||
let color_vec = model.material().get_base_color_alpha(
|
||||
Vector2::new(0.0, 0.0)
|
||||
).map(|comp| comp * 255.0);
|
||||
|
||||
color_at_isec = [color_vec[0] as u8, color_vec[1] as u8, color_vec[2] as u8, color_vec[3] as u8]
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
//make pixel opaque if intersection is found
|
||||
match clostest_intersection_point {
|
||||
Some(_) => {
|
||||
pixel_color = Rgba::from(color_at_isec);
|
||||
}
|
||||
None {} => {}
|
||||
}
|
||||
|
||||
pixel_color
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue