Skip to content

Commit

Permalink
Use indices instead of Arc for materials in Scene
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Oom committed Jul 19, 2024
1 parent 263b550 commit ae732ba
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 69 deletions.
9 changes: 5 additions & 4 deletions kdtree-tester/src/ray_bouncer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,12 @@ impl RayBouncer {
return Some(intersection);
};
let intersection = intersection.reference?;
let triangle = &self.scene.triangle_data[intersection.index as usize];
let triangle = &self.scene.triangles[intersection.index as usize];
let intersection = intersection.intersection;

let wi = -ray.direction;
let n = triangle.normals.lerp(intersection.u, intersection.v);
let uv = triangle.texcoords.lerp(intersection.u, intersection.v);
let material = triangle.material.as_ref();

// TODO: How to chose offset?
let offset = 0.00001 * n;
let point = ray.param(intersection.t);
Expand All @@ -88,7 +86,10 @@ impl RayBouncer {
return Some(checked.clone());
}

let sample = material.sample(&IncomingRay { wi, n, uv }, &mut rng);
let sample = self
.scene
.get_material(triangle)
.sample(&IncomingRay { wi, n, uv }, &mut rng);
let next_ray = Ray::new(
if sample.wo.dot(n) >= 0.0 {
point_above
Expand Down
115 changes: 60 additions & 55 deletions scene/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use geometry::{geometry::Geometry, triangle::Triangle};
use glam::{Vec2, Vec3};
use std::{collections::BTreeMap, fs::File, io::BufReader, path::Path, sync::Arc};
use std::{collections::BTreeMap, fs::File, io::BufReader, path::Path};
use wavefront::{mtl, obj};

pub mod camera;
Expand Down Expand Up @@ -42,63 +42,22 @@ impl TriangleTexcoords {
}
}

pub struct TriangleData {
pub struct SceneTriangle {
pub triangle: Triangle,
pub normals: TriangleNormals,
pub texcoords: TriangleTexcoords,
pub material: Arc<MaterialModel>,
pub material_index: usize,
}

pub struct Scene {
pub triangle_data: Vec<TriangleData>,
pub triangles: Vec<SceneTriangle>,
pub materials: Vec<MaterialModel>,
pub cameras: Vec<Camera>,
pub lights: Vec<SphericalLight>,
pub environment: Vec3,
}

fn collect_triangle_data(
image_directory: &Path,
obj: &obj::Obj,
mtl: &mtl::Mtl,
) -> Vec<TriangleData> {
let materials = materials_from_mtl(image_directory, mtl);
obj.chunks
.iter()
.flat_map(|chunk| {
chunk.faces.iter().map(|face| {
if face.points.len() != 3 {
panic!(
"Only tringular faces supported but found {} vertices.",
face.points.len()
);
}
let triangle = Triangle {
v0: obj.index_vertex(&face.points[0]).into(),
v1: obj.index_vertex(&face.points[1]).into(),
v2: obj.index_vertex(&face.points[2]).into(),
};
let normals = TriangleNormals {
n0: obj.index_normal(&face.points[0]).into(),
n1: obj.index_normal(&face.points[1]).into(),
n2: obj.index_normal(&face.points[2]).into(),
};
let texcoords = TriangleTexcoords {
uv0: obj.index_texcoord(&face.points[0]).into(),
uv1: obj.index_texcoord(&face.points[1]).into(),
uv2: obj.index_texcoord(&face.points[2]).into(),
};
TriangleData {
triangle,
normals,
texcoords,
material: materials[chunk.material.as_str()].clone(),
}
})
})
.collect::<Vec<_>>()
}

fn blend_from_mtl(image_directory: &Path, material: &mtl::Material) -> Arc<MaterialModel> {
fn blend_from_mtl(image_directory: &Path, material: &mtl::Material) -> MaterialModel {
let texture = (!material.diffuse_map.is_empty()).then(|| {
image::open(image_directory.join(&material.diffuse_map))
.unwrap()
Expand Down Expand Up @@ -129,13 +88,13 @@ fn blend_from_mtl(image_directory: &Path, material: &mtl::Material) -> Arc<Mater
second: transparency_blend,
factor: material.reflection_90_degrees,
};
Arc::new(material)
material
}

fn materials_from_mtl<'m>(
image_directory: &Path,
mtl: &'m mtl::Mtl,
) -> BTreeMap<&'m str, Arc<MaterialModel>> {
) -> BTreeMap<&'m str, MaterialModel> {
mtl.materials
.iter()
.map(|m| (m.name.as_str(), blend_from_mtl(image_directory, m)))
Expand Down Expand Up @@ -172,8 +131,47 @@ fn collect_lights(mtl: &mtl::Mtl) -> Vec<SphericalLight> {

impl Scene {
pub fn from_wavefront(image_directory: &Path, obj: &obj::Obj, mtl: &mtl::Mtl) -> Scene {
let materials = materials_from_mtl(image_directory, mtl);
let triangles = obj.chunks.iter().flat_map(|chunk| {
chunk.faces.iter().map(|face| {
if face.points.len() != 3 {
panic!(
"Only tringular faces supported but found {} vertices.",
face.points.len()
);
}
let triangle = Triangle {
v0: obj.index_vertex(&face.points[0]).into(),
v1: obj.index_vertex(&face.points[1]).into(),
v2: obj.index_vertex(&face.points[2]).into(),
};
let normals = TriangleNormals {
n0: obj.index_normal(&face.points[0]).into(),
n1: obj.index_normal(&face.points[1]).into(),
n2: obj.index_normal(&face.points[2]).into(),
};
let texcoords = TriangleTexcoords {
uv0: obj.index_texcoord(&face.points[0]).into(),
uv1: obj.index_texcoord(&face.points[1]).into(),
uv2: obj.index_texcoord(&face.points[2]).into(),
};
let material_index = materials
.iter()
.enumerate()
.find(|m| m.1 .0 == &chunk.material)
.unwrap()
.0;
SceneTriangle {
triangle,
normals,
texcoords,
material_index,
}
})
});
Scene {
triangle_data: collect_triangle_data(image_directory, obj, mtl),
triangles: triangles.collect(),
materials: materials.into_iter().map(|m| m.1).collect(),
cameras: collect_cameras(mtl),
lights: collect_lights(mtl),
environment: Vec3::new(0.8, 0.8, 0.8),
Expand All @@ -197,14 +195,21 @@ impl Scene {

println!("Collecting scene...");
let scene = Scene::from_wavefront(mtl_path.parent().unwrap(), &obj, &mtl);
println!(" Triangles: {}", scene.triangle_data.len());
println!(" Triangles: {}", scene.triangles.len());
scene
}

#[inline]
pub fn get_triangle(&self, index: u32) -> &SceneTriangle {
&self.triangles[index as usize]
}

#[inline]
pub fn get_material(&self, triangle: &SceneTriangle) -> &MaterialModel {
&self.materials[triangle.material_index]
}

pub fn collect_geometries_as_vec(&self) -> Vec<Geometry> {
self.triangle_data
.iter()
.map(|t| t.triangle.into())
.collect()
self.triangles.iter().map(|t| t.triangle.into()).collect()
}
}
14 changes: 10 additions & 4 deletions tracing/src/pathtracer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ impl Pathtracer {
return accumulated_radiance + accumulated_transport * self.scene.environment;
}
let intersection = intersection.unwrap();
let triangle = &self.scene.triangle_data[intersection.index as usize];
let triangle = self.scene.get_triangle(intersection.index);
let intersection = intersection.intersection;

ray_logger
Expand All @@ -56,7 +56,6 @@ impl Pathtracer {
let wi = -ray.direction;
let n = triangle.normals.lerp(intersection.u, intersection.v);
let uv = triangle.texcoords.lerp(intersection.u, intersection.v);
let material = triangle.material.as_ref();

// TODO: How to chose offset?
let offset = 0.00001 * n;
Expand All @@ -75,13 +74,20 @@ impl Pathtracer {
}
let wo = shadow_ray.direction.normalize();
let radiance = light.emitted(point);
material.brdf(&OutgoingRay { wi, n, wo, uv }) * radiance * wo.dot(n).abs()
let brdf = self
.scene
.get_material(triangle)
.brdf(&OutgoingRay { wi, n, wo, uv });
brdf * radiance * wo.dot(n).abs()
})
.sum();

let accumulated_radiance = accumulated_radiance + accumulated_transport * incoming_radiance;

let sample = material.sample(&IncomingRay { wi, n, uv }, rng);
let sample = self
.scene
.get_material(triangle)
.sample(&IncomingRay { wi, n, uv }, rng);
let next_ray = Ray::new(
if sample.wo.dot(n) >= 0.0 {
point_above
Expand Down
14 changes: 8 additions & 6 deletions tracing/src/raytracer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
use geometry::ray::Ray;
use glam::{UVec2, Vec2, Vec3};
use kdtree::{intersection::KdIntersection, KdTree};
use scene::{camera::Pinhole, material::MaterialModel, Scene};
use scene::{camera::Pinhole, Scene};

pub struct Raytracer {
pub scene: Scene,
Expand All @@ -30,7 +30,7 @@ impl Raytracer {
return self.scene.environment;
}
let intersection = intersection.unwrap();
let triangle = &self.scene.triangle_data[intersection.index as usize];
let triangle = self.scene.get_triangle(intersection.index);
let intersection = intersection.intersection;

let wi = -ray.direction;
Expand All @@ -45,16 +45,18 @@ impl Raytracer {
.lights
.iter()
.map(|light| {
let this = &self;
let material: &MaterialModel = &triangle.material;
let direction = light.center - point;
let shadow_ray = Ray::new(offset_point, direction);
if this.intersect_any(&shadow_ray, 0.0..=1.0) {
if self.intersect_any(&shadow_ray, 0.0..=1.0) {
return Vec3::ZERO;
}
let wo = direction.normalize();
let radiance = light.emitted(point);
material.brdf(&OutgoingRay { wi, n, wo, uv }) * radiance * wo.dot(n).abs()
let brdf = self
.scene
.get_material(triangle)
.brdf(&OutgoingRay { wi, n, wo, uv });
brdf * radiance * wo.dot(n).abs()
})
.sum()
}
Expand Down

0 comments on commit ae732ba

Please sign in to comment.