Skip to content

Commit

Permalink
Add texture support
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Oom committed May 6, 2024
1 parent fe0011a commit 8cba35e
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 19 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion kdtree-tester-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ impl RayBouncer {

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?
Expand All @@ -159,7 +160,7 @@ impl RayBouncer {
return Some(*checked);
}

let sample = material.sample(&IncomingRay { wi, n }, rng);
let sample = material.sample(&IncomingRay { wi, n, uv }, rng);
let next_ray = Ray {
origin: if sample.wo.dot(&n) >= 0.0 {
point_above
Expand Down
1 change: 1 addition & 0 deletions scene/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ edition = "2021"

[dependencies]
geometry = { version = "1.0.0", path = "../geometry" }
image = { version = "0.25.1", default-features = false }
nalgebra = { version = "0.32.5", default-features = false }
simba = { version = "0.8.1", default-features = false, features = ["std"] }
wavefront = { version = "1.0.0", path = "../wavefront" }
35 changes: 27 additions & 8 deletions scene/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ pub struct TriangleTexcoords {
pub uv2: Vector2<f32>,
}

impl TriangleTexcoords {
pub fn lerp(&self, u: f32, v: f32) -> Vector2<f32> {
(1.0 - (u + v)) * self.uv0 + u * self.uv1 + v * self.uv2
}
}

pub struct TriangleData {
pub triangle: Triangle,
pub normals: TriangleNormals,
Expand All @@ -50,8 +56,12 @@ pub struct Scene {
pub environment: Vector3<f32>,
}

fn collect_triangle_data(obj: &obj::Obj, mtl: &mtl::Mtl) -> Vec<TriangleData> {
let materials = materials_from_mtl(mtl);
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| {
Expand Down Expand Up @@ -82,9 +92,15 @@ fn collect_triangle_data(obj: &obj::Obj, mtl: &mtl::Mtl) -> Vec<TriangleData> {
.collect::<Vec<_>>()
}

fn blend_from_mtl(material: &mtl::Material) -> Arc<MaterialModel> {
fn blend_from_mtl(image_directory: &Path, material: &mtl::Material) -> Arc<MaterialModel> {
let texture = (!material.diffuse_map.is_empty()).then(|| {
image::open(image_directory.join(&material.diffuse_map))
.unwrap()
.to_rgb32f()
});
let reflection = DiffuseReflectiveMaterial {
reflectance: material.diffuse_reflection.into(),
texture,
};
let refraction = SpecularRefractiveMaterial {
index_of_refraction: material.index_of_refraction,
Expand All @@ -110,10 +126,13 @@ fn blend_from_mtl(material: &mtl::Material) -> Arc<MaterialModel> {
Arc::new(material)
}

fn materials_from_mtl(mtl: &mtl::Mtl) -> BTreeMap<&str, Arc<MaterialModel>> {
fn materials_from_mtl<'p, 'm>(
image_directory: &'p Path,
mtl: &'m mtl::Mtl,
) -> BTreeMap<&'m str, Arc<MaterialModel>> {
mtl.materials
.iter()
.map(|m| (m.name.as_str(), blend_from_mtl(m)))
.map(|m| (m.name.as_str(), blend_from_mtl(image_directory, m)))
.collect::<BTreeMap<_, _>>()
}

Expand Down Expand Up @@ -146,9 +165,9 @@ fn collect_lights(mtl: &mtl::Mtl) -> Vec<SphericalLight> {
}

impl Scene {
pub fn from_wavefront(obj: &obj::Obj, mtl: &mtl::Mtl) -> Scene {
pub fn from_wavefront(image_directory: &Path, obj: &obj::Obj, mtl: &mtl::Mtl) -> Scene {
Scene {
triangle_data: collect_triangle_data(obj, mtl),
triangle_data: collect_triangle_data(image_directory, obj, mtl),
cameras: collect_cameras(mtl),
lights: collect_lights(mtl),
environment: Vector3::new(0.8, 0.8, 0.8),
Expand All @@ -171,7 +190,7 @@ impl Scene {
println!(" Cameras: {}", mtl.cameras.len());

println!("Collecting scene...");
let scene = Scene::from_wavefront(&obj, &mtl);
let scene = Scene::from_wavefront(mtl_path.parent().unwrap(), &obj, &mtl);
println!(" Triangles: {}", scene.triangle_data.len());
scene
}
Expand Down
2 changes: 2 additions & 0 deletions scene/src/material.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use image::Rgb32FImage;
use nalgebra::{UnitVector3, Vector3};

#[derive(Debug, PartialEq)]
Expand All @@ -10,6 +11,7 @@ pub struct MaterialSample {
#[derive(Clone, Debug)]
pub struct DiffuseReflectiveMaterial {
pub reflectance: Vector3<f32>,
pub texture: Option<Rgb32FImage>,
}

#[derive(Clone, Debug)]
Expand Down
29 changes: 23 additions & 6 deletions tracing/src/material.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use nalgebra::{RealField, UnitVector3, Vector3};
use nalgebra::{RealField, UnitVector3, Vector2, Vector3};
use rand::{rngs::SmallRng, Rng};
use scene::material::{
BlendMaterial, DiffuseReflectiveMaterial, FresnelBlendMaterial, MaterialSample,
Expand All @@ -23,17 +23,23 @@ fn is_same_sign(a: f32, b: f32) -> bool {
pub struct IncomingRay {
pub wi: Vector3<f32>,
pub n: UnitVector3<f32>,
pub uv: Vector2<f32>,
}

impl IncomingRay {
fn with_normal(&self, n: UnitVector3<f32>) -> IncomingRay {
IncomingRay { wi: self.wi, n }
IncomingRay {
wi: self.wi,
n,
uv: self.uv,
}
}

fn with_wo(&self, wo: Vector3<f32>) -> OutgoingRay {
OutgoingRay {
wi: self.wi,
n: self.n,
uv: self.uv,
wo,
}
}
Expand All @@ -47,6 +53,7 @@ impl IncomingRay {
pub struct OutgoingRay {
pub wi: Vector3<f32>,
pub n: UnitVector3<f32>,
pub uv: Vector2<f32>,
pub wo: Vector3<f32>,
}

Expand All @@ -59,6 +66,7 @@ impl OutgoingRay {
IncomingRay {
wi: self.wi,
n: self.n,
uv: self.uv,
}
}
}
Expand All @@ -70,8 +78,15 @@ pub trait Material {
}

impl Material for DiffuseReflectiveMaterial {
fn brdf(&self, _: &OutgoingRay) -> Vector3<f32> {
self.reflectance * f32::frac_1_pi()
fn brdf(&self, outgoing: &OutgoingRay) -> Vector3<f32> {
if let Some(texture) = &self.texture {
let px = (texture.width() as f32 * outgoing.uv.x).floor();
let py = (texture.height() as f32 * outgoing.uv.y).floor();
let reflectance: Vector3<f32> = texture[(px as u32, py as u32)].0.into();
reflectance * f32::frac_1_pi()
} else {
self.reflectance * f32::frac_1_pi()
}
}

fn sample(&self, incoming: &IncomingRay, rng: &mut SmallRng) -> MaterialSample {
Expand Down Expand Up @@ -205,7 +220,8 @@ mod specular_refractive_material_tests {
};
let wi = Vector3::new(-1.0, 2.0, 0.0).normalize();
let n = UnitVector3::new_normalize(Vector3::new(0.0, 1.0, 0.0));
let incoming = IncomingRay { wi, n };
let uv = Vector2::zeros();
let incoming = IncomingRay { wi, n, uv };
let mut rng = SmallRng::seed_from_u64(0);

let actual = material.sample(&incoming, &mut rng);
Expand All @@ -225,7 +241,8 @@ mod specular_refractive_material_tests {
};
let wi = Vector3::new(-1.0, -2.0, 0.0).normalize();
let n = UnitVector3::new_normalize(Vector3::new(0.0, 1.0, 0.0));
let incoming = IncomingRay { wi, n };
let uv = Vector2::zeros();
let incoming = IncomingRay { wi, n, uv };
let mut rng = SmallRng::seed_from_u64(0);

let actual = material.sample(&incoming, &mut rng);
Expand Down
5 changes: 3 additions & 2 deletions tracing/src/pathtracer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ 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?
Expand All @@ -97,7 +98,7 @@ impl Pathtracer {
let wo = shadow_ray.direction.normalize();
let radiance = light.emitted(point);
material
.brdf(&OutgoingRay { wi, n, wo })
.brdf(&OutgoingRay { wi, n, wo, uv })
.component_mul(&radiance)
* wo.dot(&n).abs()
})
Expand All @@ -106,7 +107,7 @@ impl Pathtracer {
let accumulated_radiance =
accumulated_radiance + accumulated_transport.component_mul(&incoming_radiance);

let sample = material.sample(&IncomingRay { wi, n }, pixel.rng);
let sample = material.sample(&IncomingRay { wi, n, uv }, pixel.rng);
let next_ray = Ray {
origin: if sample.wo.dot(&n) >= 0.0 {
point_above
Expand Down
6 changes: 4 additions & 2 deletions tracing/src/raytracer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ impl Raytracer {
offset_point: Vector3<f32>,
wi: Vector3<f32>,
n: UnitVector3<f32>,
uv: Vector2<f32>,
light: &SphericalLight,
) -> Vector3<f32> {
let direction = light.center - target;
Expand All @@ -44,7 +45,7 @@ impl Raytracer {
let wo = direction.normalize();
let radiance = light.emitted(target);
material
.brdf(&OutgoingRay { wi, n, wo })
.brdf(&OutgoingRay { wi, n, wo, uv })
.component_mul(&radiance)
* wo.dot(&n).abs()
}
Expand All @@ -60,6 +61,7 @@ impl Raytracer {
let wi = -ray.direction;
let point = ray.param(intersection.t);
let n = triangle.normals.lerp(intersection.u, intersection.v);
let uv = triangle.texcoords.lerp(intersection.u, intersection.v);

// TODO: How to chose offset?
let offset_point = point + 0.0001 * n.into_inner();
Expand All @@ -68,7 +70,7 @@ impl Raytracer {
self.scene
.lights
.iter()
.map(|light| self.light_contribution(material, point, offset_point, wi, n, light))
.map(|light| self.light_contribution(material, point, offset_point, wi, n, uv, light))
.sum()
}

Expand Down

0 comments on commit 8cba35e

Please sign in to comment.