ft: quad support
This commit is contained in:
@@ -27,8 +27,7 @@ fn main() {
|
|||||||
pretty_env_logger::init();
|
pretty_env_logger::init();
|
||||||
|
|
||||||
// TODO: use cli arg for scenefile
|
// TODO: use cli arg for scenefile
|
||||||
let json_file = "./scenes/withTriangle.json";
|
let json_file = "./scenes/scene.json";
|
||||||
// let json_file = "./scenes/scene.json";
|
|
||||||
let json_str = fs::read_to_string(json_file).expect("Reading specified scene file failed!");
|
let json_str = fs::read_to_string(json_file).expect("Reading specified scene file failed!");
|
||||||
let mut scene: Scene = serde_json::from_str(&json_str).unwrap();
|
let mut scene: Scene = serde_json::from_str(&json_str).unwrap();
|
||||||
scene.render();
|
scene.render();
|
||||||
|
|||||||
@@ -2,4 +2,5 @@ pub mod hit;
|
|||||||
pub mod materials;
|
pub mod materials;
|
||||||
pub mod sphere;
|
pub mod sphere;
|
||||||
pub mod triangle;
|
pub mod triangle;
|
||||||
|
pub mod quad;
|
||||||
pub mod traits;
|
pub mod traits;
|
||||||
|
|||||||
84
src/objects/quad.rs
Normal file
84
src/objects/quad.rs
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
use crate::objects::hit::Hit;
|
||||||
|
use crate::objects::sphere::Sphere;
|
||||||
|
use crate::objects::traits::Hittable;
|
||||||
|
use crate::objects::triangle::Triangle;
|
||||||
|
use crate::ray::Ray;
|
||||||
|
use crate::{objects::materials::traits::Material, vec3::Vec3};
|
||||||
|
use log::info;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct Quad {
|
||||||
|
p1: Vec3,
|
||||||
|
p2: Vec3,
|
||||||
|
p3: Vec3,
|
||||||
|
p4: Vec3,
|
||||||
|
material: Arc<dyn Material>,
|
||||||
|
normal: Vec3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Quad {
|
||||||
|
pub fn new(p1: Vec3, p2: Vec3, p3: Vec3, p4: Vec3, material: Arc<dyn Material>) -> Self {
|
||||||
|
Self {
|
||||||
|
p1,
|
||||||
|
p2,
|
||||||
|
p3,
|
||||||
|
p4,
|
||||||
|
material,
|
||||||
|
normal: (p2 - p1).cross(&(p4 - p1)).get_unit(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn corner_spheres(&self) -> Vec<Sphere> {
|
||||||
|
let mut out: Vec<Sphere> = vec![];
|
||||||
|
out.push(Sphere::new(self.p1, 1., self.material.clone()));
|
||||||
|
out.push(Sphere::new(self.p2, 1., self.material.clone()));
|
||||||
|
out.push(Sphere::new(self.p3, 1., self.material.clone()));
|
||||||
|
out.push(Sphere::new(self.p4, 1., self.material.clone()));
|
||||||
|
return out;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Quad {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("Triangle")
|
||||||
|
.field("p1", &self.p1)
|
||||||
|
.field("p2", &self.p2)
|
||||||
|
.field("p3", &self.p3)
|
||||||
|
.field("p4", &self.p4)
|
||||||
|
.field("material", &self.material)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hittable for Quad {
|
||||||
|
fn hit(&self, r: &Ray) -> Option<Hit> {
|
||||||
|
let isct1 = Triangle::hit(
|
||||||
|
self.p1,
|
||||||
|
self.p2,
|
||||||
|
self.p4,
|
||||||
|
self.material.clone(),
|
||||||
|
self.normal,
|
||||||
|
r,
|
||||||
|
);
|
||||||
|
let isct2 = Triangle::hit(
|
||||||
|
self.p2,
|
||||||
|
self.p3,
|
||||||
|
self.p4,
|
||||||
|
self.material.clone(),
|
||||||
|
self.normal,
|
||||||
|
r,
|
||||||
|
);
|
||||||
|
if isct1.is_some() {
|
||||||
|
return isct1;
|
||||||
|
}
|
||||||
|
if isct2.is_some() {
|
||||||
|
}
|
||||||
|
return isct2;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normal_at(&self, _p: &Vec3) -> Vec3 {
|
||||||
|
// FIXME: might cause ownership issues
|
||||||
|
return self.normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
|
use log::{info, warn};
|
||||||
|
|
||||||
use crate::objects::hit::Hit;
|
use crate::objects::hit::Hit;
|
||||||
use crate::objects::traits::Hittable;
|
use crate::objects::traits::Hittable;
|
||||||
use crate::ray::Ray;
|
use crate::ray::Ray;
|
||||||
use crate::{objects::materials::traits::Material, vec3::Vec3};
|
use crate::{objects::materials::traits::Material, vec3::Vec3};
|
||||||
use is_close::default;
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@@ -21,7 +22,43 @@ impl Triangle {
|
|||||||
p2,
|
p2,
|
||||||
p3,
|
p3,
|
||||||
material,
|
material,
|
||||||
normal: (p2 - p1).cross(&(p3 - p1)),
|
normal: (p2 - p1).cross(&(p3 - p1)).get_unit(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hit(
|
||||||
|
p1: Vec3,
|
||||||
|
p2: Vec3,
|
||||||
|
p3: Vec3,
|
||||||
|
material: Arc<dyn Material>,
|
||||||
|
normal: Vec3,
|
||||||
|
r: &Ray,
|
||||||
|
) -> Option<Hit> {
|
||||||
|
// check if ray parallel to plane
|
||||||
|
let dot = normal.dot(r.dir());
|
||||||
|
if dot == 0.0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let d = (-normal).dot(&p1);
|
||||||
|
// hitpoint on plane
|
||||||
|
let t = -(normal.dot(&(r.origin() + d))) / dot;
|
||||||
|
// hits behind camera
|
||||||
|
if t < 0. {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
let p = r.at(t);
|
||||||
|
let a4 = (p3 - p1).cross(&(p2 - p1)).length();
|
||||||
|
let a3 = (p3 - p).cross(&(p2 - p)).length();
|
||||||
|
let a2 = (p3 - p).cross(&(p1 - p)).length();
|
||||||
|
let a1 = (p2 - p).cross(&(p1 - p)).length();
|
||||||
|
|
||||||
|
let diff = (a4 - a1 - a2 - a3).abs();
|
||||||
|
if diff < 0.001 {
|
||||||
|
return Some(Hit::new(t, p, normal, material, normal.dot(&-r.dir()) < 0.));
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,38 +75,15 @@ impl Debug for Triangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Hittable for Triangle {
|
impl Hittable for Triangle {
|
||||||
fn hit(&self, r: &Ray) -> Option<super::hit::Hit> {
|
fn hit(&self, r: &Ray) -> Option<Hit> {
|
||||||
// check if ray parallel to plane
|
Triangle::hit(
|
||||||
let dot = self.normal.dot(r.dir());
|
self.p1,
|
||||||
if default().is_close(dot, 0.) {
|
self.p2,
|
||||||
return None;
|
self.p3,
|
||||||
}
|
self.material.clone(),
|
||||||
|
self.normal,
|
||||||
let d = (-self.normal).dot(&self.p1);
|
r,
|
||||||
// hitpoint on plane
|
)
|
||||||
let t = -(self.normal.dot(&(r.origin() + d))) / dot;
|
|
||||||
// hits behind camera
|
|
||||||
if t < 0. {
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let p = *r.origin() + t * r.dir();
|
|
||||||
let a4 = (self.p3 - self.p1).cross(&(self.p2 - self.p1)).length();
|
|
||||||
let a3 = (self.p3 - p).cross(&(self.p2 - p)).length();
|
|
||||||
let a2 = (self.p3 - p).cross(&(self.p1 - p)).length();
|
|
||||||
let a1 = (self.p2 - p).cross(&(self.p1 - p)).length();
|
|
||||||
|
|
||||||
let mut normal_copy = self.normal.clone();
|
|
||||||
let diff = (a4 - a1 - a2 - a3).abs();
|
|
||||||
if diff < 0.01 {
|
|
||||||
if self.normal.dot(&-r.dir()) < 0. {
|
|
||||||
normal_copy *= -1.; // TODO: vec3 * integer function
|
|
||||||
}
|
|
||||||
return Some(Hit::new(t, p, self.normal, self.material.clone(), true)); // TODO:
|
|
||||||
// front_face calculation; have to change with if check up there iggg
|
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn normal_at(&self, _p: &Vec3) -> Vec3 {
|
fn normal_at(&self, _p: &Vec3) -> Vec3 {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use crate::{camera::Camera, vec3::Vec3};
|
|||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct RawCamera {
|
pub struct RawCamera {
|
||||||
// output
|
// output
|
||||||
image_width: u32,
|
image_width: u32,
|
||||||
image_height: u32,
|
image_height: u32,
|
||||||
|
|
||||||
// raytracing
|
// raytracing
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
@@ -12,6 +12,7 @@ use crate::{
|
|||||||
lambertian::{Lambertian, Metal},
|
lambertian::{Lambertian, Metal},
|
||||||
traits::Material,
|
traits::Material,
|
||||||
},
|
},
|
||||||
|
quad::Quad,
|
||||||
sphere::Sphere,
|
sphere::Sphere,
|
||||||
traits::Hittable,
|
traits::Hittable,
|
||||||
triangle::Triangle,
|
triangle::Triangle,
|
||||||
@@ -28,7 +29,11 @@ pub struct Scene {
|
|||||||
|
|
||||||
impl Debug for Scene {
|
impl Debug for Scene {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.debug_struct("Scene").field("camera", &self.camera).field("materials", &self.materials).field("objects", &self.objects).finish()
|
f.debug_struct("Scene")
|
||||||
|
.field("camera", &self.camera)
|
||||||
|
.field("materials", &self.materials)
|
||||||
|
.field("objects", &self.objects)
|
||||||
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,11 +105,21 @@ struct RawTriangle {
|
|||||||
pub material: u32,
|
pub material: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct RawQuad {
|
||||||
|
pub p1: Vec3,
|
||||||
|
pub p2: Vec3,
|
||||||
|
pub p3: Vec3,
|
||||||
|
pub p4: Vec3,
|
||||||
|
pub material: u32,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(tag = "type", rename_all = "lowercase")]
|
#[serde(tag = "type", rename_all = "lowercase")]
|
||||||
enum HittableDef {
|
enum HittableDef {
|
||||||
Sphere(RawSphere),
|
Sphere(RawSphere),
|
||||||
Triangle(RawTriangle),
|
Triangle(RawTriangle),
|
||||||
|
Quad(RawQuad),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HittableDef {
|
impl HittableDef {
|
||||||
@@ -140,6 +155,22 @@ impl HittableDef {
|
|||||||
materials.get(t.material as usize).unwrap().clone(),
|
materials.get(t.material as usize).unwrap().clone(),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
HittableDef::Quad(q) => {
|
||||||
|
if q.material as usize >= materials.len() {
|
||||||
|
warn!(
|
||||||
|
"Quad specified nonexistent material {}; skipping...",
|
||||||
|
q.material
|
||||||
|
);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(Arc::new(Quad::new(
|
||||||
|
q.p1,
|
||||||
|
q.p2,
|
||||||
|
q.p3,
|
||||||
|
q.p4,
|
||||||
|
materials.get(q.material as usize).unwrap().clone(),
|
||||||
|
)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
28
src/vec3.rs
28
src/vec3.rs
@@ -1,13 +1,13 @@
|
|||||||
use core::f32::math::sqrt;
|
use core::f32::math::sqrt;
|
||||||
use is_close::default;
|
use is_close::default;
|
||||||
use rand::RngExt;
|
use rand::RngExt;
|
||||||
use serde::Deserialize;
|
use serde::{Deserialize, Serialize, Serializer};
|
||||||
use std::{
|
use std::{
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
|
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Deserialize)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct Vec3 {
|
pub struct Vec3 {
|
||||||
x: f32,
|
x: f32,
|
||||||
y: f32,
|
y: f32,
|
||||||
@@ -156,6 +156,29 @@ impl Vec3 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Serialize for Vec3 {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
([self.x, self.y, self.z] as [f32; 3]).serialize(serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Vec3 {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let arr = <[f32; 3]>::deserialize(deserializer)?;
|
||||||
|
Ok(Self {
|
||||||
|
x: arr[0],
|
||||||
|
y: arr[1],
|
||||||
|
z: arr[2],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for Vec3 {
|
impl Default for Vec3 {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -222,7 +245,6 @@ impl Add<f32> for &Vec3 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Add<f32> for Vec3 {
|
impl Add<f32> for Vec3 {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user