Skip to content

Commit

Permalink
Chap 15: triangles
Browse files Browse the repository at this point in the history
(smooth triangles)
  • Loading branch information
fremag committed Feb 19, 2024
1 parent 11b8937 commit c33adf9
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 17 deletions.
Binary file added img/teapot_smooth.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion ray-tracer-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::scenes::dragon_scene::DragonScene;
use crate::scenes::group_scene::GroupScene;
use crate::scenes::patterns_scene::PatternsScene;
use crate::scenes::refraction_sphere_scene::RefractionSphereScene;
use crate::scenes::smooth_teapot_scene::SmoothTeaPotScene;
use crate::scenes::stripe_pattern_scene::StripePatternScene;
use crate::scenes::teapot_scene::TeaPotScene;

Expand All @@ -28,7 +29,7 @@ fn main() {
}

println!("Start...");
render(&TeaPotScene{},400, 400, "./img/teapot.png");
render(&SmoothTeaPotScene{},400, 400, "./img/teapot_smooth.png");
println!("Done.")
}

Expand All @@ -45,6 +46,7 @@ fn render_all() {
render(&RefractionSphereScene{},400, 400, "./img/refraction_sphere_scene.png");
render(&TeaPotScene{},400, 400, "./img/teapot.png");
render(&DragonScene { }, 800, 600, "./img/dragon.png");
render(&SmoothTeaPotScene{},400, 400, "./img/teapot_smooth.png");
}

fn render(scene : &dyn Scene, h_size : usize, v_size : usize, file_path: &str) {
Expand Down
1 change: 1 addition & 0 deletions ray-tracer-cli/src/scenes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ pub mod stripe_pattern_scene;
pub mod clover_triangles_scene;
pub mod teapot_scene;
pub mod dragon_scene;
pub mod smooth_teapot_scene;
43 changes: 43 additions & 0 deletions ray-tracer-cli/src/scenes/smooth_teapot_scene.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use std::env;
use std::fs::File;
use ray_tracer_lib::camera::Camera;
use ray_tracer_lib::colors::Color;
use ray_tracer_lib::core::math::PI;
use ray_tracer_lib::core::transform::{rotation_x, rotation_y, rotation_z, view_transform};
use ray_tracer_lib::core::tuple::{point, vector};
use ray_tracer_lib::lights::point_light::PointLight;
use ray_tracer_lib::obj_reader::ObjReader;
use ray_tracer_lib::object::Object;
use ray_tracer_lib::world::World;
use crate::scene::Scene;

pub struct SmoothTeaPotScene {}

impl Scene for SmoothTeaPotScene {
fn get_world(&self) -> World {
println!("{}", env::current_dir().unwrap().display());
let file_path = r"./obj/teapot.obj";
let file = File::open(file_path).unwrap();

let mut obj_reader = ObjReader::new(file);
obj_reader.read();

let teapot = obj_reader.smooth_models;
let teapot_model= teapot.get("Teapot001").unwrap();
let mut obj_teapot = Object::new_smooth_triangle(teapot_model.clone());
obj_teapot.set_transformation(&rotation_y(-PI/4.0) * &(&rotation_x(-PI/2.0)*&rotation_z(PI/2.0)));
let mut world = World::new();
world.objects.push(obj_teapot);
let lights = vec!(PointLight::new(point(-100.0, 100.0, -100.0), Color::new(1.0, 1.0, 1.0)));
world.set_lights(lights);
world
}

fn get_camera(&self, h_size: usize, v_size: usize) -> Camera {
let mut camera = Camera::new(h_size, v_size, PI / 3.0);
camera.set_transform(view_transform(point(-15.0, 15.0, -30.0),
point(0.0, 1.0, 0.0),
vector(0.0, 1.0, 0.0)));
camera
}
}
60 changes: 49 additions & 11 deletions ray-tracer-lib/src/obj_reader.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
use std::collections::HashMap;
use std::io::{BufRead, BufReader};
use crate::core::math::Float;
use crate::core::tuple::{point, Tuple};
use crate::core::tuple::{point, Tuple, vector};
use crate::shapes::smooth_triangle::SmoothTriangle;
use crate::shapes::smooth_triangle_model::SmoothTriangleModel;
use crate::shapes::triangle::Triangle;
use crate::shapes::triangle_model::TriangleModel;

pub struct ObjReader<T> {
pub source : T,
pub vertices : Vec<Tuple>,
pub normals : Vec<Tuple>,
pub triangles : Vec<Triangle>,
pub smooth_triangles : Vec<SmoothTriangle>,
pub models: HashMap<String, TriangleModel>,
pub smooth_models: HashMap<String, SmoothTriangleModel>,
}

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

pub fn read(&mut self) {
let reader = BufReader::new(&mut self.source);
Expand All @@ -30,6 +39,13 @@ impl<T> ObjReader<T> where T: std::io::Read {
let z = items[3].parse::<Float>().unwrap();
self.vertices.push(point(x, y, z));
}
if line.starts_with("vn ") {
let items : Vec<&str> = line.split(' ').collect();
let x = items[1].parse::<Float>().unwrap();
let y = items[2].parse::<Float>().unwrap();
let z = items[3].parse::<Float>().unwrap();
self.normals.push(vector(x, y, z));
}
if line.starts_with("f ") {
let items: Vec<&str> = line.split(' ').filter(|item| ! item.is_empty()).collect();
for i in 1..items.len()-2 {
Expand All @@ -42,24 +58,46 @@ impl<T> ObjReader<T> where T: std::io::Read {
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 s1.len() == 3 {
let i_n1 = s1[2].parse::<usize>().unwrap() - 1;
let i_n2 = s2[2].parse::<usize>().unwrap() - 1;
let i_n3 = s3[2].parse::<usize>().unwrap() - 1;
let n1 = self.normals[i_n1];
let n2 = self.normals[i_n2];
let n3 = self.normals[i_n3];
let smooth_triangle = SmoothTriangle::new(*v1, *v2, *v3, n1, n2, n3);
self.smooth_triangles.push(smooth_triangle);
} else {
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);

if self.triangles.len() > 0 {
let triangle_model = TriangleModel::new(self.triangles.clone());
self.models.insert(current_name.to_string(), triangle_model);
self.triangles = vec![];
} else {
let smooth_triangle_model = SmoothTriangleModel::new(self.smooth_triangles.clone());
self.smooth_models.insert(current_name.to_string(), smooth_triangle_model);
self.smooth_triangles = vec![];
}
current_name = name;
self.triangles = vec![];
}
}
}
}
let triangle_model = TriangleModel::new(self.triangles.clone());
self.models.insert(current_name.to_string(), triangle_model);
self.triangles = vec![];
if self.triangles.len() > 0 {
let triangle_model = TriangleModel::new(self.triangles.clone());
self.models.insert(current_name.to_string(), triangle_model);
self.triangles = vec![];
} else {
let smooth_triangle_model = SmoothTriangleModel::new(self.smooth_triangles.clone());
self.smooth_models.insert(current_name.to_string(), smooth_triangle_model);
self.smooth_triangles = vec![];
}
}
}
4 changes: 0 additions & 4 deletions ray-tracer-lib/src/shapes/smooth_triangle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@ impl SmoothTriangle {
let b= self.n3 * intersection.v;
let c = self.n1 * (1.0 - intersection.u - intersection.v);
let n = a+b+c;
print!("{} {} {}", a.x, a.y, a.z);
print!("{} {} {}", b.x, b.y, b.z);
print!("{} {} {}", c.x, c.y, c.z);
print!("{} {} {}", n.x, n.y, n.z);
n.normalize()
}

Expand Down
47 changes: 46 additions & 1 deletion ray-tracer-lib/src/tests/obj_reader_tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#[cfg(test)]
mod tests {
use crate::core::tuple::point;
use crate::core::tuple::{point, vector};
use crate::obj_reader::ObjReader;

#[test]
Expand Down Expand Up @@ -113,4 +113,49 @@ f 1 3 4
assert_eq!(t2.p2, obj_reader.vertices[2]);
assert_eq!(t2.p3, obj_reader.vertices[3]);
}

#[test]
fn vertex_normal_records_test() {
let str = "
vn 0 0 1
vn 0.707 0 -0.707
vn 1 2 3
";
let mut obj_reader = ObjReader::new(str.as_bytes());
obj_reader.read();
assert_eq!(obj_reader.normals[0], vector(0.0, 0.0, 1.0));
assert_eq!(obj_reader.normals[1], vector(0.707, 0.0, -0.707));
assert_eq!(obj_reader.normals[2], vector(1.0, 2.0, 3.0));
}

#[test]
fn faces_with_normals_test() {
let str = "
v 0 1 0
v -1 0 0
v 1 0 0
vn -1 0 0
vn 1 0 0
vn 0 1 0
f 1//3 2//1 3//2
f 1/0/3 2/102/1 3/14/2
";

let mut obj_reader = ObjReader::new(str.as_bytes());
obj_reader.read();
let t1 = &obj_reader.smooth_triangles[0];
assert_eq!(t1.triangle.p1, point(0.0, 1.0, 0.0));
assert_eq!(t1.triangle.p2, point(-1.0, 0.0, 0.0));
assert_eq!(t1.triangle.p3, point(1.0, 0.0, 0.0));
assert_eq!(t1.n1, vector(0.0, 1.0, 0.0));
assert_eq!(t1.n2, vector(-1.0, 0.0, 0.0));
assert_eq!(t1.n3, vector(1.0, 0.0, 0.0));
let t2 = &obj_reader.smooth_triangles[1];
assert_eq!(t2.triangle.p1, point(0.0, 1.0, 0.0));
assert_eq!(t2.triangle.p2, point(-1.0, 0.0, 0.0));
assert_eq!(t2.triangle.p3, point(1.0, 0.0, 0.0));
assert_eq!(t2.n1, vector(0.0, 1.0, 0.0));
assert_eq!(t2.n2, vector(-1.0, 0.0, 0.0));
assert_eq!(t2.n3, vector(1.0, 0.0, 0.0));
}
}

0 comments on commit c33adf9

Please sign in to comment.