Skip to content

Commit

Permalink
Chap 15: triangles
Browse files Browse the repository at this point in the history
(read wavefront obj file)
  • Loading branch information
fremag committed Feb 6, 2024
1 parent c46ca0d commit dffda5b
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 20 deletions.
48 changes: 32 additions & 16 deletions ray-tracer-lib/src/obj_reader.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
use std::collections::HashMap;
use std::io::{BufRead, BufReader};
use crate::core::math::Float;
use crate::core::tuple::{point, Tuple};
use crate::shapes::group::Group;
use crate::shapes::triangle::Triangle;
use crate::shapes::triangle_model::TriangleModel;

pub struct ObjReader<T> where T: std::io::Read {
pub struct ObjReader<T> {
pub source : T,
pub vertices : Vec<Tuple>,
pub triangles : Vec<crate::shapes::triangle::Triangle>,
pub triangles : Vec<Triangle>,
pub models: HashMap<String, TriangleModel>,
}

impl<T> ObjReader<T> where T: std::io::Read {
pub fn new(source : T) -> Self { Self{source, vertices: vec![], triangles: vec![] } }
pub fn new(source : T) -> Self { Self{source, vertices: vec![], triangles: vec![], models: HashMap::new() } }

pub fn read(&mut self) -> Group {
pub fn read(&mut self) {
let reader = BufReader::new(&mut self.source);
let mut current_name = String::from("Default");

for line_file in reader.lines() {
match line_file {
Expand All @@ -29,20 +32,33 @@ impl<T> ObjReader<T> where T: std::io::Read {
}
if line.starts_with("f ") {
let items: Vec<&str> = line.split(' ').collect();
let i1 = items[1].parse::<usize>().unwrap()-1;
let i2 = items[2].parse::<usize>().unwrap()-1;
let i3 = items[3].parse::<usize>().unwrap()-1;
let v1 = &self.vertices[i1];
let v2 = &self.vertices[i2];
let v3 = &self.vertices[i3];
let triangle = Triangle::new(*v1, *v2, *v3);
self.triangles.push(triangle);
for i in 1..items.len()-2 {
let i1 = items[1].parse::<usize>().unwrap() - 1;
let i2 = items[i+1].parse::<usize>().unwrap() - 1;
let i3 = items[i+2].parse::<usize>().unwrap() - 1;
let v1 = &self.vertices[i1];
let v2 = &self.vertices[i2];
let v3 = &self.vertices[i3];
let triangle = Triangle::new(*v1, *v2, *v3);
self.triangles.push(triangle);
}
}
if line.starts_with("g ") {
let items: Vec<&str> = line.split(' ').collect();
let name = String::from(items[1]);
let triangle_model = TriangleModel::new(self.triangles.clone());
self.models.insert(current_name.to_string(), triangle_model);

current_name = name;
self.triangles = vec![];
}
}
}
}

let group = Group::new();
group
if ! self.models.is_empty() {
let triangle_model = TriangleModel::new(self.triangles.clone());
self.models.insert(current_name.to_string(), triangle_model);
self.triangles = vec![];
}
}
}
11 changes: 9 additions & 2 deletions ray-tracer-lib/src/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ use crate::core::intersections::{Intersections, intersections};
use crate::material::{Material};
use crate::core::math::Float;
use crate::core::matrix::Matrix;
use crate::object::ObjectType::ObjectShape;
use crate::object::ObjectType::{ObjectShape, TriangleGroup};
use crate::shapes::plane::Plane;
use crate::core::ray::Ray;
use crate::shapes::shape::Shape;
use crate::shapes::sphere::sphere;
use crate::core::tuple::Tuple;
use crate::shapes::triangle_model::TriangleModel;

#[derive(Debug, Clone)]
pub struct Object {
Expand All @@ -26,7 +27,7 @@ pub struct Object {
}

#[derive(Debug, Clone)]
pub enum ObjectType { ObjectShape(Shape), ObjectGroup(Group)}
pub enum ObjectType { ObjectShape(Shape), ObjectGroup(Group), TriangleGroup(TriangleModel)}

impl Object {
pub fn group(&self) -> Option<&Group> {
Expand All @@ -51,6 +52,7 @@ impl Object {
let local_normal = match &self.object_type {
ObjectShape(shape) => shape.normal_at(local_point),
ObjectGroup(_) => panic!("No !"),
TriangleGroup(_) => panic!("No !"),
};
let n = self.normal_to_world(&local_normal);
n
Expand All @@ -61,13 +63,15 @@ impl Object {
return match &self.object_type {
ObjectShape(shape) => intersections(shape.intersect(&ray2).iter().map(|t| Intersection::new(*t, &self )).collect()),
ObjectGroup(group) => group.intersect(&ray2),
TriangleGroup(model) => model.intersect(&ray2),
};
}

pub fn bounds(&self) -> Bounds {
return match &self.object_type {
ObjectShape(shape) => shape.bounds().transform(&self.transformation),
ObjectGroup(group) => group.bounds(),
TriangleGroup(model) => model.bounds()
};
}

Expand All @@ -82,6 +86,9 @@ impl Object {
self.transformation_inverse = self.transformation.inverse();
self.transformation_inverse_transpose = self.transformation_inverse.transpose();
}
TriangleGroup(model) => {
model.set_transformation(transformation);
}
}
self
}
Expand Down
1 change: 1 addition & 0 deletions ray-tracer-lib/src/shapes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ pub mod plane;
pub mod sphere;
pub mod shape;
pub mod triangle;
pub mod triangle_model;
28 changes: 28 additions & 0 deletions ray-tracer-lib/src/shapes/triangle_model.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use crate::core::bounds::Bounds;
use crate::core::intersections::Intersections;
use crate::core::matrix::Matrix;
use crate::core::ray::Ray;
use crate::shapes::triangle::Triangle;

#[derive(Debug, Clone)]
pub struct TriangleModel {
pub triangles : Vec<Triangle>
}

impl TriangleModel {
pub fn new(triangles : Vec<Triangle>) -> Self {
Self {triangles}
}

pub(crate) fn set_transformation(&self, transformation: Matrix<4>) {
todo!()
}

pub(crate) fn bounds(&self) -> Bounds {
todo!()
}

pub(crate) fn intersect(&self, ray: &Ray) -> Intersections {
todo!()
}
}
56 changes: 54 additions & 2 deletions ray-tracer-lib/src/tests/obj_reader_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ in a relative way,\n
and came back the previous night.\n
";
let mut obj_reader = ObjReader::new(str.as_bytes());
let group = obj_reader.read();
assert_eq!(group.len(), 0);
obj_reader.read();
assert!(obj_reader.triangles.is_empty());
}

#[test]
Expand Down Expand Up @@ -69,4 +69,56 @@ f 1 3 4\n
assert_eq!(obj_reader.triangles[1].p2, obj_reader.vertices[2]);
assert_eq!(obj_reader.triangles[1].p3, obj_reader.vertices[3]);
}

#[test]
fn triangulating_polygons_test() {
let str =
"
v -1 1 0
v -1 0 0
v 1 0 0
v 1 1 0
v 0 2 0
f 1 2 3 4 5
";
let mut obj_reader = ObjReader::new(str.as_bytes());
obj_reader.read();
assert_eq!(obj_reader.triangles[0].p1, obj_reader.vertices[0]);
assert_eq!(obj_reader.triangles[0].p2, obj_reader.vertices[1]);
assert_eq!(obj_reader.triangles[0].p3, obj_reader.vertices[2]);
assert_eq!(obj_reader.triangles[1].p1, obj_reader.vertices[0]);
assert_eq!(obj_reader.triangles[1].p2, obj_reader.vertices[2]);
assert_eq!(obj_reader.triangles[1].p3, obj_reader.vertices[3]);
assert_eq!(obj_reader.triangles[2].p1, obj_reader.vertices[0]);
assert_eq!(obj_reader.triangles[2].p2, obj_reader.vertices[3]);
assert_eq!(obj_reader.triangles[2].p3, obj_reader.vertices[4]);
}

#[test]
fn triangles_in_groups_test() {
let str =
"
v -1 1 0
v -1 0 0
v 1 0 0
v 1 1 0
g FirstGroup
f 1 2 3
g SecondGroup
f 1 3 4
";
let mut obj_reader = ObjReader::new(str.as_bytes());
obj_reader.read();

assert!(obj_reader.models.contains_key("FirstGroup"));
assert!(obj_reader.models.contains_key("SecondGroup"));
let t1 = obj_reader.models["FirstGroup"].triangles[0];
let t2 = obj_reader.models["SecondGroup"].triangles[0];
assert_eq!(t1.p1, obj_reader.vertices[0]);
assert_eq!(t1.p2, obj_reader.vertices[1]);
assert_eq!(t1.p3, obj_reader.vertices[2]);
assert_eq!(t2.p1, obj_reader.vertices[0]);
assert_eq!(t2.p2, obj_reader.vertices[2]);
assert_eq!(t2.p3, obj_reader.vertices[3]);
}
}

0 comments on commit dffda5b

Please sign in to comment.