middle of attempting to fix rotations

This commit is contained in:
CDaut 2023-11-22 11:52:04 +01:00
parent 6cbd93aad0
commit 8657806aba
10 changed files with 692 additions and 78 deletions

View file

@ -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() }
}

View file

@ -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
View 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() }
}

View file

@ -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
}