Add Texture struct to add extra texture information
This commit is contained in:
parent
07445dd4be
commit
20c32fc467
|
@ -40,7 +40,7 @@ fn main() -> std::io::Result<()> {
|
||||||
|
|
||||||
let scene = Scene {
|
let scene = Scene {
|
||||||
objects: vec![
|
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(),
|
lights: Vec::new(),
|
||||||
background: Color::black()
|
background: Color::black()
|
||||||
|
|
|
@ -22,8 +22,8 @@ pub trait Surface {
|
||||||
fn normal(&self, point: Point3f) -> Unit3f;
|
fn normal(&self, point: Point3f) -> Unit3f;
|
||||||
|
|
||||||
// Takes in a point (assumed to be on the object's surface)
|
// Takes in a point (assumed to be on the object's surface)
|
||||||
// and returns the color information on that point.
|
// and returns the texture information on that point.
|
||||||
fn getcolor(&self, point: Point3f) -> Color;
|
fn gettexture(&self, point: Point3f) -> Texture;
|
||||||
|
|
||||||
// Creates a bounding sphere around the object.
|
// Creates a bounding sphere around the object.
|
||||||
fn bound(&self) -> Bound;
|
fn bound(&self) -> Bound;
|
||||||
|
@ -51,12 +51,12 @@ impl Object {
|
||||||
} else { None }
|
} else { None }
|
||||||
}
|
}
|
||||||
pub fn normal(&self, point: Point3f) -> Unit3f { self.surface.normal(point) }
|
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 {
|
pub trait Light {
|
||||||
// Determine if the light is able to illuminate the point.
|
// 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<Object>) -> Option<Color>;
|
fn illuminate(&self, point: Point3f, objects: &Vec<Object>) -> Option<Color>;
|
||||||
|
|
||||||
// Return the direction from the point to the light source.
|
// Return the direction from the point to the light source.
|
||||||
|
|
|
@ -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).
|
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).
|
y_axis: Vector3f, // Plane y-axis (The 3D direction that corresponds to the y-direction on the plane).
|
||||||
|
|
||||||
texture: Box<dyn Fn(f32, f32) -> Color> // Texture map.
|
texture: Box<dyn Fn(f32, f32) -> Texture> // Texture map.
|
||||||
// Input coordinates are defined in terms of the axes above.
|
// Input coordinates are defined in terms of the axes above.
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
impl Plane {
|
impl Plane {
|
||||||
// Creates a new plane.
|
// Creates a new plane.
|
||||||
pub fn new<F: 'static>(center: Point3f, x_axis: Vector3f, y_axis: Vector3f, texture: F) -> Self
|
pub fn new<F: 'static>(center: Point3f, x_axis: Vector3f, y_axis: Vector3f, texture: F) -> Self
|
||||||
where F: Fn(f32, f32) -> Color
|
where F: Fn(f32, f32) -> Texture
|
||||||
{
|
{
|
||||||
Plane {
|
Plane {
|
||||||
center: center,
|
center: center,
|
||||||
|
@ -34,7 +34,7 @@ impl Plane {
|
||||||
|
|
||||||
// Creates a new plane with the normal flipped.
|
// Creates a new plane with the normal flipped.
|
||||||
pub fn new_flip<F: 'static>(center: Point3f, x_axis: Vector3f, y_axis: Vector3f, texture: F) -> Self
|
pub fn new_flip<F: 'static>(center: Point3f, x_axis: Vector3f, y_axis: Vector3f, texture: F) -> Self
|
||||||
where F: Fn(f32, f32) -> Color
|
where F: Fn(f32, f32) -> Texture
|
||||||
{
|
{
|
||||||
Plane {
|
Plane {
|
||||||
center: center,
|
center: center,
|
||||||
|
@ -46,20 +46,20 @@ impl Plane {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a new plane of a solid color.
|
// Creates a new plane of a solid color.
|
||||||
pub fn new_solid(center: Point3f, x_axis: Vector3f, y_axis: Vector3f, color: Color) -> Self
|
pub fn new_solid(center: Point3f, x_axis: Vector3f, y_axis: Vector3f, texture: Texture) -> Self
|
||||||
{ Plane::new(center, x_axis, y_axis, move |_, _| color) }
|
{ Plane::new(center, x_axis, y_axis, move |_, _| texture) }
|
||||||
|
|
||||||
// Creates a new flipped plane of a solid color.
|
// 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
|
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 |_, _| color) }
|
{ Plane::new_flip(center, x_axis, y_axis, move |_, _| texture) }
|
||||||
|
|
||||||
|
|
||||||
// Creates a new XY-plane with the given texture map.
|
// Creates a new XY-plane with the given texture map.
|
||||||
pub fn xy<F: 'static + Fn(f32, f32) -> Color>(texture: F) -> Self
|
pub fn xy(texture: impl 'static + Fn(f32, f32) -> Texture) -> Self
|
||||||
{ Plane::new(Point3::origin(), Vector3::x(), Vector3::y(), texture) }
|
{ Plane::new(Point3::origin(), Vector3::x(), Vector3::y(), texture) }
|
||||||
|
|
||||||
// Creates a new XZ-plane with the given texture map.
|
// Creates a new XZ-plane with the given texture map.
|
||||||
pub fn xz<F: 'static + Fn(f32, f32) -> Color>(texture: F) -> Self
|
pub fn xz(texture: impl 'static + Fn(f32, f32) -> Texture) -> Self
|
||||||
{ Plane::new(Point3::origin(), Vector3::x(), Vector3::z(), texture) }
|
{ 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 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 rel_pos = point - self.center;
|
||||||
let proj_point3 = rel_pos - (*self.normal * self.normal.dot(&rel_pos));
|
let proj_point3 = rel_pos - (*self.normal * self.normal.dot(&rel_pos));
|
||||||
|
|
||||||
|
|
|
@ -12,15 +12,15 @@ pub struct Sphere {
|
||||||
pub center: Point3f, // Center point of the sphere.
|
pub center: Point3f, // Center point of the sphere.
|
||||||
pub radius: f32, // Radius of the sphere.
|
pub radius: f32, // Radius of the sphere.
|
||||||
|
|
||||||
texture: Box<dyn Fn(f32, f32) -> Color> // Texture map.
|
texture: Box<dyn Fn(f32, f32) -> Texture> // Texture map.
|
||||||
// Uses spherical coordinates (normalized from 0-1) as input.
|
// Uses spherical coordinates (normalized from 0-1) as input.
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
impl Sphere {
|
impl Sphere {
|
||||||
// Creates a new sphere.
|
// Creates a new sphere.
|
||||||
pub fn new<F: 'static>(x: f32, y: f32, z: f32, radius: f32, texture: F) -> Self
|
pub fn new<F: 'static>(x: f32, y: f32, z: f32, radius: f32, texture: F) -> Self
|
||||||
where F: Fn(f32, f32) -> Color
|
where F: Fn(f32, f32) -> Texture
|
||||||
{
|
{
|
||||||
Sphere {
|
Sphere {
|
||||||
center: Point3::new(x, y, z),
|
center: Point3::new(x, y, z),
|
||||||
|
@ -30,8 +30,8 @@ impl Sphere {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a new sphere of a solid color.
|
// Creates a new sphere of a solid color.
|
||||||
pub fn new_solid(x: f32, y: f32, z: f32, radius: f32, color: Color) -> Self
|
pub fn new_solid(x: f32, y: f32, z: f32, radius: f32, texture: Texture) -> Self
|
||||||
{ Sphere::new(x, y, z, radius, move |_, _| color) }
|
{ Sphere::new(x, y, z, radius, move |_, _| texture) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Surface for Sphere {
|
impl Surface for Sphere {
|
||||||
|
@ -66,7 +66,7 @@ impl Surface for Sphere {
|
||||||
Unit::new_normalize(point - self.center)
|
Unit::new_normalize(point - self.center)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getcolor(&self, point: Point3f) -> Color {
|
fn gettexture(&self, point: Point3f) -> Texture {
|
||||||
let normal = self.normal(point);
|
let normal = self.normal(point);
|
||||||
|
|
||||||
// In this particular case, the normal is simular to a point on a unit sphere
|
// In this particular case, the normal is simular to a point on a unit sphere
|
||||||
|
|
|
@ -16,8 +16,8 @@ pub struct Triangle {
|
||||||
normal: Unit3f, // Precalculated normal vector.
|
normal: Unit3f, // Precalculated normal vector.
|
||||||
area: f32, // Precalculated area for barycentric calculations.
|
area: f32, // Precalculated area for barycentric calculations.
|
||||||
|
|
||||||
texture: Box<dyn Fn(f32, f32, f32) -> Color> // Texture map.
|
texture: Box<dyn Fn(f32, f32, f32) -> Texture> // Texture map.
|
||||||
// Uses barycentric coordinates as input.
|
// Uses barycentric coordinates as input.
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TriangleMesh {
|
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)))
|
self.intersect_(vertices, ray).map(|(t, u, v)| distance(&ray.origin, &self.from_bary(vertices, t, u, v)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getcolor(&self, vertices: &Vec<Point3f>, point: Point3f) -> Color {
|
fn gettexture(&self, vertices: &Vec<Point3f>, point: Point3f) -> Texture {
|
||||||
let (t, u, v) = self.to_bary(vertices, point);
|
let (t, u, v) = self.to_bary(vertices, point);
|
||||||
(*self.texture)(t, u, v)
|
(*self.texture)(t, u, v)
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ impl Triangle {
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
impl TriangleMesh {
|
impl TriangleMesh {
|
||||||
pub fn new(vertices: Vec<Point3f>, tris: Vec<(usize, usize, usize, Box<dyn Fn(f32, f32, f32) -> Color>)>) -> Self {
|
pub fn new(vertices: Vec<Point3f>, tris: Vec<(usize, usize, usize, Box<dyn Fn(f32, f32, f32) -> Texture>)>) -> Self {
|
||||||
let triangles = tris.into_iter()
|
let triangles = tris.into_iter()
|
||||||
.map(|(v1, v2, v3, f)| Triangle {
|
.map(|(v1, v2, v3, f)| Triangle {
|
||||||
v1: v1,
|
v1: v1,
|
||||||
|
@ -102,7 +102,7 @@ impl TriangleMesh {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_solid(vertices: Vec<Point3f>, tris: Vec<(usize, usize, usize)>, color: Color) -> Self {
|
pub fn new_solid(vertices: Vec<Point3f>, tris: Vec<(usize, usize, usize)>, texture: Texture) -> Self {
|
||||||
let triangles = tris.into_iter()
|
let triangles = tris.into_iter()
|
||||||
.map(|(v1, v2, v3)| Triangle {
|
.map(|(v1, v2, v3)| Triangle {
|
||||||
v1: v1,
|
v1: v1,
|
||||||
|
@ -110,7 +110,7 @@ impl TriangleMesh {
|
||||||
v3: v3,
|
v3: v3,
|
||||||
normal: Unit::new_normalize((&vertices[v2] - &vertices[v1]).cross(&(&vertices[v3] - &vertices[v1]))),
|
normal: Unit::new_normalize((&vertices[v2] - &vertices[v1]).cross(&(&vertices[v3] - &vertices[v1]))),
|
||||||
area: tri_area(&vertices[v1], &vertices[v2], &vertices[v3]),
|
area: tri_area(&vertices[v1], &vertices[v2], &vertices[v3]),
|
||||||
texture: Box::new(move |_, _, _| color)
|
texture: Box::new(move |_, _, _| texture)
|
||||||
}).collect();
|
}).collect();
|
||||||
TriangleMesh {
|
TriangleMesh {
|
||||||
vertices: vertices,
|
vertices: vertices,
|
||||||
|
@ -119,11 +119,11 @@ impl TriangleMesh {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn singleton<F: 'static>(vertex1: Point3f, vertex2: Point3f, vertex3: Point3f, texture: F) -> Self
|
pub fn singleton<F: 'static>(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))]) }
|
{ 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
|
pub fn singleton_solid(vertex1: Point3f, vertex2: Point3f, vertex3: Point3f, texture: Texture) -> Self
|
||||||
{ TriangleMesh::singleton(vertex1, vertex2, vertex3, move |_, _, _| color) }
|
{ TriangleMesh::singleton(vertex1, vertex2, vertex3, move |_, _, _| texture) }
|
||||||
|
|
||||||
|
|
||||||
fn closest_tri(&self, point: Point3f) -> &Triangle {
|
fn closest_tri(&self, point: Point3f) -> &Triangle {
|
||||||
|
@ -159,8 +159,8 @@ impl Surface for TriangleMesh {
|
||||||
self.closest_tri(point).normal
|
self.closest_tri(point).normal
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getcolor(&self, point: Point3f) -> Color {
|
fn gettexture(&self, point: Point3f) -> Texture {
|
||||||
self.closest_tri(point).getcolor(&self.vertices, point)
|
self.closest_tri(point).gettexture(&self.vertices, point)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uses Welzl's algorithm to solve the bounding sphere problem
|
// Uses Welzl's algorithm to solve the bounding sphere problem
|
||||||
|
|
|
@ -18,8 +18,8 @@ fn trace(ray: Ray, objects: &Vec<Object>) -> Option<(&Object, f32)> {
|
||||||
pub fn cast_ray(ray: Ray, scene: &Scene) -> Color {
|
pub fn cast_ray(ray: Ray, scene: &Scene) -> Color {
|
||||||
if let Some((obj, dist)) = trace(ray, &scene.objects) {
|
if let Some((obj, dist)) = trace(ray, &scene.objects) {
|
||||||
let point = ray.project(dist);
|
let point = ray.project(dist);
|
||||||
let surface_color = obj.getcolor(point);
|
let surface_texture = obj.gettexture(point);
|
||||||
surface_color
|
surface_texture.color
|
||||||
}
|
}
|
||||||
else { scene.background }
|
else { scene.background }
|
||||||
}
|
}
|
||||||
|
|
16
src/types.rs
16
src/types.rs
|
@ -97,3 +97,19 @@ impl Mul<f32> 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue