diff --git a/src/main.rs b/src/main.rs index 8c0d281..9a3e779 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,7 +40,7 @@ fn main() -> std::io::Result<()> { let scene = Scene { objects: vec![ - Object::new(TriangleMesh::singleton(Point3::new(-1.0, -1.0, 2.0), Point3::new(0.0, 1.0, 2.0), Point3::new(1.0, -1.0, 2.0), |t, u, v| Color::new(t, u, v))) + Object::new(TriangleMesh::singleton(Point3::new(-1.0, -1.0, 2.0), Point3::new(0.0, 1.0, 2.0), Point3::new(1.0, -1.0, 2.0), |t, u, v| Texture::new(t, u, v, 0.18))) ], lights: Vec::new(), background: Color::black() diff --git a/src/object.rs b/src/object.rs index eb7276e..54f1ebf 100644 --- a/src/object.rs +++ b/src/object.rs @@ -22,8 +22,8 @@ pub trait Surface { fn normal(&self, point: Point3f) -> Unit3f; // Takes in a point (assumed to be on the object's surface) - // and returns the color information on that point. - fn getcolor(&self, point: Point3f) -> Color; + // and returns the texture information on that point. + fn gettexture(&self, point: Point3f) -> Texture; // Creates a bounding sphere around the object. fn bound(&self) -> Bound; @@ -51,12 +51,12 @@ impl Object { } else { None } } pub fn normal(&self, point: Point3f) -> Unit3f { self.surface.normal(point) } - pub fn getcolor(&self, point: Point3f) -> Color { self.surface.getcolor(point) } + pub fn gettexture(&self, point: Point3f) -> Texture { self.surface.gettexture(point) } } pub trait Light { // Determine if the light is able to illuminate the point. - // If so, return the color of the light. + // If so, return the light amount recieved. fn illuminate(&self, point: Point3f, objects: &Vec) -> Option; // Return the direction from the point to the light source. diff --git a/src/object/plane.rs b/src/object/plane.rs index fca079d..687f955 100644 --- a/src/object/plane.rs +++ b/src/object/plane.rs @@ -13,15 +13,15 @@ pub struct Plane { x_axis: Vector3f, // Plane x-axis (The 3D direction that corresponds to the x-direction on the plane). y_axis: Vector3f, // Plane y-axis (The 3D direction that corresponds to the y-direction on the plane). - texture: Box Color> // Texture map. - // Input coordinates are defined in terms of the axes above. + texture: Box Texture> // Texture map. + // Input coordinates are defined in terms of the axes above. } #[allow(dead_code)] impl Plane { // Creates a new plane. pub fn new(center: Point3f, x_axis: Vector3f, y_axis: Vector3f, texture: F) -> Self - where F: Fn(f32, f32) -> Color + where F: Fn(f32, f32) -> Texture { Plane { center: center, @@ -34,7 +34,7 @@ impl Plane { // Creates a new plane with the normal flipped. pub fn new_flip(center: Point3f, x_axis: Vector3f, y_axis: Vector3f, texture: F) -> Self - where F: Fn(f32, f32) -> Color + where F: Fn(f32, f32) -> Texture { Plane { center: center, @@ -46,20 +46,20 @@ impl Plane { } // Creates a new plane of a solid color. - pub fn new_solid(center: Point3f, x_axis: Vector3f, y_axis: Vector3f, color: Color) -> Self - { Plane::new(center, x_axis, y_axis, move |_, _| color) } + pub fn new_solid(center: Point3f, x_axis: Vector3f, y_axis: Vector3f, texture: Texture) -> Self + { Plane::new(center, x_axis, y_axis, move |_, _| texture) } // Creates a new flipped plane of a solid color. - pub fn new_solid_flip(center: Point3f, x_axis: Vector3f, y_axis: Vector3f, color: Color) -> Self - { Plane::new_flip(center, x_axis, y_axis, move |_, _| color) } + pub fn new_solid_flip(center: Point3f, x_axis: Vector3f, y_axis: Vector3f, texture: Texture) -> Self + { Plane::new_flip(center, x_axis, y_axis, move |_, _| texture) } // Creates a new XY-plane with the given texture map. - pub fn xy Color>(texture: F) -> Self + pub fn xy(texture: impl 'static + Fn(f32, f32) -> Texture) -> Self { Plane::new(Point3::origin(), Vector3::x(), Vector3::y(), texture) } // Creates a new XZ-plane with the given texture map. - pub fn xz Color>(texture: F) -> Self + pub fn xz(texture: impl 'static + Fn(f32, f32) -> Texture) -> Self { Plane::new(Point3::origin(), Vector3::x(), Vector3::z(), texture) } } @@ -77,7 +77,7 @@ impl Surface for Plane { fn normal(&self, _point: Point3f) -> Unit3f { self.normal } - fn getcolor(&self, point: Point3f) -> Color { + fn gettexture(&self, point: Point3f) -> Texture { let rel_pos = point - self.center; let proj_point3 = rel_pos - (*self.normal * self.normal.dot(&rel_pos)); diff --git a/src/object/sphere.rs b/src/object/sphere.rs index 7e20c63..bc774ee 100644 --- a/src/object/sphere.rs +++ b/src/object/sphere.rs @@ -12,15 +12,15 @@ pub struct Sphere { pub center: Point3f, // Center point of the sphere. pub radius: f32, // Radius of the sphere. - texture: Box Color> // Texture map. - // Uses spherical coordinates (normalized from 0-1) as input. + texture: Box Texture> // Texture map. + // Uses spherical coordinates (normalized from 0-1) as input. } #[allow(dead_code)] impl Sphere { // Creates a new sphere. pub fn new(x: f32, y: f32, z: f32, radius: f32, texture: F) -> Self - where F: Fn(f32, f32) -> Color + where F: Fn(f32, f32) -> Texture { Sphere { center: Point3::new(x, y, z), @@ -30,8 +30,8 @@ impl Sphere { } // Creates a new sphere of a solid color. - pub fn new_solid(x: f32, y: f32, z: f32, radius: f32, color: Color) -> Self - { Sphere::new(x, y, z, radius, move |_, _| color) } + pub fn new_solid(x: f32, y: f32, z: f32, radius: f32, texture: Texture) -> Self + { Sphere::new(x, y, z, radius, move |_, _| texture) } } impl Surface for Sphere { @@ -66,7 +66,7 @@ impl Surface for Sphere { Unit::new_normalize(point - self.center) } - fn getcolor(&self, point: Point3f) -> Color { + fn gettexture(&self, point: Point3f) -> Texture { let normal = self.normal(point); // In this particular case, the normal is simular to a point on a unit sphere diff --git a/src/object/triangle.rs b/src/object/triangle.rs index 6f109ed..39dccd6 100644 --- a/src/object/triangle.rs +++ b/src/object/triangle.rs @@ -16,8 +16,8 @@ pub struct Triangle { normal: Unit3f, // Precalculated normal vector. area: f32, // Precalculated area for barycentric calculations. - texture: Box Color> // Texture map. - // Uses barycentric coordinates as input. + texture: Box Texture> // Texture map. + // Uses barycentric coordinates as input. } pub struct TriangleMesh { @@ -78,7 +78,7 @@ impl Triangle { self.intersect_(vertices, ray).map(|(t, u, v)| distance(&ray.origin, &self.from_bary(vertices, t, u, v))) } - fn getcolor(&self, vertices: &Vec, point: Point3f) -> Color { + fn gettexture(&self, vertices: &Vec, point: Point3f) -> Texture { let (t, u, v) = self.to_bary(vertices, point); (*self.texture)(t, u, v) } @@ -86,7 +86,7 @@ impl Triangle { #[allow(dead_code)] impl TriangleMesh { - pub fn new(vertices: Vec, tris: Vec<(usize, usize, usize, Box Color>)>) -> Self { + pub fn new(vertices: Vec, tris: Vec<(usize, usize, usize, Box Texture>)>) -> Self { let triangles = tris.into_iter() .map(|(v1, v2, v3, f)| Triangle { v1: v1, @@ -102,7 +102,7 @@ impl TriangleMesh { } } - pub fn new_solid(vertices: Vec, tris: Vec<(usize, usize, usize)>, color: Color) -> Self { + pub fn new_solid(vertices: Vec, tris: Vec<(usize, usize, usize)>, texture: Texture) -> Self { let triangles = tris.into_iter() .map(|(v1, v2, v3)| Triangle { v1: v1, @@ -110,7 +110,7 @@ impl TriangleMesh { v3: v3, normal: Unit::new_normalize((&vertices[v2] - &vertices[v1]).cross(&(&vertices[v3] - &vertices[v1]))), area: tri_area(&vertices[v1], &vertices[v2], &vertices[v3]), - texture: Box::new(move |_, _, _| color) + texture: Box::new(move |_, _, _| texture) }).collect(); TriangleMesh { vertices: vertices, @@ -119,11 +119,11 @@ impl TriangleMesh { } pub fn singleton(vertex1: Point3f, vertex2: Point3f, vertex3: Point3f, texture: F) -> Self - where F: Fn(f32, f32, f32) -> Color + where F: Fn(f32, f32, f32) -> Texture { TriangleMesh::new(vec![vertex1, vertex2, vertex3], vec![(0, 1, 2, Box::new(texture))]) } - pub fn singleton_solid(vertex1: Point3f, vertex2: Point3f, vertex3: Point3f, color: Color) -> Self - { TriangleMesh::singleton(vertex1, vertex2, vertex3, move |_, _, _| color) } + pub fn singleton_solid(vertex1: Point3f, vertex2: Point3f, vertex3: Point3f, texture: Texture) -> Self + { TriangleMesh::singleton(vertex1, vertex2, vertex3, move |_, _, _| texture) } fn closest_tri(&self, point: Point3f) -> &Triangle { @@ -159,8 +159,8 @@ impl Surface for TriangleMesh { self.closest_tri(point).normal } - fn getcolor(&self, point: Point3f) -> Color { - self.closest_tri(point).getcolor(&self.vertices, point) + fn gettexture(&self, point: Point3f) -> Texture { + self.closest_tri(point).gettexture(&self.vertices, point) } // Uses Welzl's algorithm to solve the bounding sphere problem diff --git a/src/render.rs b/src/render.rs index 133b7d8..7daeab3 100644 --- a/src/render.rs +++ b/src/render.rs @@ -18,8 +18,8 @@ fn trace(ray: Ray, objects: &Vec) -> Option<(&Object, f32)> { pub fn cast_ray(ray: Ray, scene: &Scene) -> Color { if let Some((obj, dist)) = trace(ray, &scene.objects) { let point = ray.project(dist); - let surface_color = obj.getcolor(point); - surface_color + let surface_texture = obj.gettexture(point); + surface_texture.color } else { scene.background } } diff --git a/src/types.rs b/src/types.rs index 5594066..2ab6885 100644 --- a/src/types.rs +++ b/src/types.rs @@ -97,3 +97,19 @@ impl Mul for Color { } } } + +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Texture { + pub color: Color, + pub albedo: f32 +} + +#[allow(dead_code)] +impl Texture { + pub fn new(red: f32, green: f32, blue: f32, albedo: f32) -> Self { + Texture { + color: Color::new(red, green, blue), + albedo: albedo + } + } +}