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 d023526 commit 5a7f37f
Show file tree
Hide file tree
Showing 7 changed files with 41 additions and 10 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.

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" }
7 changes: 7 additions & 0 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 Down Expand Up @@ -85,6 +91,7 @@ fn collect_triangle_data(obj: &obj::Obj, mtl: &mtl::Mtl) -> Vec<TriangleData> {
fn blend_from_mtl(material: &mtl::Material) -> Arc<MaterialModel> {
let reflection = DiffuseReflectiveMaterial {
reflectance: material.diffuse_reflection.into(),
texture: material.diffuse_map.as_ref().map(|img| img.to_rgb32f()),
};
let refraction = SpecularRefractiveMaterial {
index_of_refraction: material.index_of_refraction,
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 5a7f37f

Please sign in to comment.