First quick pass at loading OBJ files.

This commit is contained in:
Matthew Gordon 2019-12-21 09:11:30 -05:00
parent 199b33f944
commit 3618636c42
3 changed files with 106 additions and 26 deletions

View File

@ -7,9 +7,12 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
sdl2 = "0.32" alga = "0.9"
itertools = "0.8"
obj = "0.9"
quickcheck = "0.9" quickcheck = "0.9"
quickcheck_macros = "0.8" quickcheck_macros = "0.8"
sdl2 = "0.32"
[dependencies.nalgebra] [dependencies.nalgebra]
version = "0.19" version = "0.19"

View File

@ -7,15 +7,17 @@ use std::time::Duration;
use nalgebra::{Point3, Vector3}; use nalgebra::{Point3, Vector3};
use std::cmp::min; use std::cmp::min;
use std::rc::Rc; use std::rc::Rc;
use std::path::Path;
use vanrijn::camera::partial_render_scene; use vanrijn::camera::partial_render_scene;
use vanrijn::colour::{ColourRgbF, NamedColour}; use vanrijn::colour::{ColourRgbF, NamedColour};
use vanrijn::image::{ClampingToneMapper, ImageRgbF, ImageRgbU8, ToneMapper}; use vanrijn::image::{ClampingToneMapper, ImageRgbF, ImageRgbU8, ToneMapper};
use vanrijn::materials::{LambertianMaterial, PhongMaterial, ReflectiveMaterial}; use vanrijn::materials::{LambertianMaterial, PhongMaterial, ReflectiveMaterial};
use vanrijn::mesh::Triangle; use vanrijn::mesh::{load_obj, Triangle};
use vanrijn::raycasting::{Plane, Sphere}; use vanrijn::raycasting::{Intersect, Plane, Sphere};
use vanrijn::scene::Scene; use vanrijn::scene::Scene;
fn update_texture(image: &ImageRgbU8, texture: &mut Texture) { fn update_texture(image: &ImageRgbU8, texture: &mut Texture) {
@ -59,9 +61,20 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
)?; )?;
let mut output_image = ImageRgbF::<f64>::new(image_width, image_height); let mut output_image = ImageRgbF::<f64>::new(image_width, image_height);
let scene = Scene { let scene = Arc::new(Scene {
camera_location: Point3::new(0.0, 0.0, 0.0), camera_location: Point3::new(-2.0, 1.0, -5.0),
objects: vec![ objects: load_obj(
Path::new("/home/matthew/Downloads/bunny.obj"),
Arc::new(ReflectiveMaterial {
colour: ColourRgbF::from_named(NamedColour::Yellow),
diffuse_strength: 0.05,
reflection_strength: 0.9,
}),
)
.unwrap()
.into_iter()
.map(|triangle| Box::new(triangle) as Box<dyn Intersect<f64>>)
.chain(vec![
Box::new(Plane::new( Box::new(Plane::new(
Vector3::new(0.0, 1.0, 0.0), Vector3::new(0.0, 1.0, 0.0),
-2.0, -2.0,
@ -69,17 +82,17 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
colour: ColourRgbF::new(0.55, 0.27, 0.04), colour: ColourRgbF::new(0.55, 0.27, 0.04),
diffuse_strength: 0.1, diffuse_strength: 0.1,
}), }),
)), )) as Box<dyn Intersect<f64>>,
Box::new(Sphere::new( Box::new(Sphere::new(
Point3::new(1.25, -0.5, 6.0), Point3::new(-6.25, -0.5, 1.0),
1.0, 1.0,
Rc::new(LambertianMaterial { Arc::new(LambertianMaterial {
colour: ColourRgbF::from_named(NamedColour::Green), colour: ColourRgbF::from_named(NamedColour::Green),
diffuse_strength: 0.1, diffuse_strength: 0.1,
}), }),
)), )),
Box::new(Sphere::new( Box::new(Sphere::new(
Point3::new(-1.25, -0.5, 6.0), Point3::new(-4.25, -0.5, 2.0),
1.0, 1.0,
Rc::new(ReflectiveMaterial { Rc::new(ReflectiveMaterial {
colour: ColourRgbF::from_named(NamedColour::Blue), colour: ColourRgbF::from_named(NamedColour::Blue),
@ -88,7 +101,7 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
}), }),
)), )),
Box::new(Sphere::new( Box::new(Sphere::new(
Point3::new(0.0, 1.5, 6.0), Point3::new(-5.0, 1.5, 1.0),
1.0, 1.0,
Rc::new(PhongMaterial { Rc::new(PhongMaterial {
colour: ColourRgbF::from_named(NamedColour::Red), colour: ColourRgbF::from_named(NamedColour::Red),
@ -97,20 +110,9 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
specular_strength: 1.0, specular_strength: 1.0,
}), }),
)), )),
Box::new(Triangle { ])
vertices: [ .collect(),
Point3::new(1.25, -0.5, 6.0), });
Point3::new(-1.25, -0.5, 6.0),
Point3::new(0.0, 1.5, 6.0),
],
normals: [Vector3::new(0.0, 0.0, 1.0); 3],
material: Rc::new(LambertianMaterial {
colour: ColourRgbF::from_named(NamedColour::Green),
diffuse_strength: 0.1,
}),
}),
],
};
let mut event_pump = sdl_context.event_pump()?; let mut event_pump = sdl_context.event_pump()?;
let mut i = 0; let mut i = 0;

View File

@ -1,10 +1,15 @@
use nalgebra::{Point3, RealField, Vector2, Vector3}; use nalgebra::{convert, Point3, RealField, Vector2, Vector3};
use obj::{IndexTuple, Obj, SimplePolygon};
use super::materials::Material; use super::materials::Material;
use super::raycasting::{Intersect, IntersectionInfo, Ray}; use super::raycasting::{Intersect, IntersectionInfo, Ray};
use std::rc::Rc; use std::rc::Rc;
use alga::general::SupersetOf;
use std::io::Result;
use std::path::Path;
#[derive(Debug)]
pub struct Triangle<T: RealField> { pub struct Triangle<T: RealField> {
pub vertices: [Point3<T>; 3], pub vertices: [Point3<T>; 3],
pub normals: [Vector3<T>; 3], pub normals: [Vector3<T>; 3],
@ -76,6 +81,76 @@ impl<T: RealField> Intersect<T> for Triangle<T> {
} }
} }
fn get_vertex_and_normal<T: RealField>(
index_tuple: &IndexTuple,
vertex_positions: &Vec<[f32; 3]>,
normal_positions: &Vec<[f32; 3]>,
) -> (Point3<T>, Vector3<T>)
where
T: SupersetOf<f32>,
{
let &IndexTuple(vertex_index, _, maybe_normal_index) = index_tuple;
let vertex: Point3<T> = convert(Point3::from_slice(&vertex_positions[vertex_index]));
let normal = match maybe_normal_index {
Some(normal_index) => convert(Vector3::from_row_slice(&normal_positions[normal_index])),
None => Vector3::zeros(),
};
(vertex, normal)
}
fn get_triangles<T: RealField>(
polygon: &SimplePolygon,
vertex_positions: &Vec<[f32; 3]>,
normal_positions: &Vec<[f32; 3]>,
material: Arc<dyn Material<T>>,
) -> Vec<Triangle<T>>
where
T: SupersetOf<f32>,
{
if let Some(v0_index) = polygon.iter().next() {
let (v0_vertex, v0_normal) =
get_vertex_and_normal(v0_index, &vertex_positions, &normal_positions);
polygon
.iter()
.skip(1)
.zip(polygon.iter().skip(2))
.map(|(v1_index, v2_index)| {
let (v1_vertex, v1_normal) =
get_vertex_and_normal(v1_index, &vertex_positions, &normal_positions);
let (v2_vertex, v2_normal) =
get_vertex_and_normal(v2_index, &vertex_positions, &normal_positions);
let vertices = [v0_vertex, v1_vertex, v2_vertex];
let normals = [v0_normal, v1_normal, v2_normal];
Triangle {
vertices,
normals,
material: material.clone(),
}
})
.collect()
} else {
vec![]
}
}
pub fn load_obj<T: RealField>(
filename: &Path,
material: Arc<dyn Material<T>>,
) -> Result<Vec<Triangle<T>>>
where
T: SupersetOf<f32>,
{
let obj = Obj::<SimplePolygon>::load(filename)?;
Ok(obj
.objects
.iter()
.flat_map(|object| object.groups.iter())
.flat_map(|group| group.polys.iter())
.flat_map(|poly| get_triangles(poly, &obj.position, &obj.normal, material.clone()))
.collect())
}
fn indices_with_index_of_largest_element_last<T: RealField>(v: &Vector3<T>) -> [usize; 3] { fn indices_with_index_of_largest_element_last<T: RealField>(v: &Vector3<T>) -> [usize; 3] {
if v.x > v.y { if v.x > v.y {
if v.z > v.x { if v.z > v.x {