Realize the triangle struct doesn't work and completely refactor it
This commit is contained in:
parent
822941d561
commit
cddec468de
|
@ -20,10 +20,11 @@ This list may be changed or extended in the future.
|
|||
- [x] Color mapping on planes
|
||||
- [ ] Triangle objects
|
||||
- [x] Triangle struct
|
||||
- [ ] Triangle intersection test
|
||||
- [ ] Triangle normal generation
|
||||
- [ ] Color mapping on triangles
|
||||
- [ ] Triangle meshes
|
||||
- [x] Triangle intersection test
|
||||
- [x] Triangle normal generation
|
||||
- [x] Color mapping on triangles
|
||||
- [x] Triangle mesh struct
|
||||
- [ ] Triangle mesh intersection test
|
||||
- [ ] Bounding boxes
|
||||
- [ ] Direct lighting
|
||||
- [ ] Point light sources
|
||||
|
|
|
@ -20,21 +20,21 @@ impl Camera {
|
|||
|
||||
// Constructs a new camera from a position and viewing direction.
|
||||
pub fn new_(pos: Point3<f32>, dir: Vector3<f32>, up: Vector3<f32>,
|
||||
focal_length: f32, aspect_ratio: f32, canvas_x: f32, image_x: u32) -> Self {
|
||||
focal_length: f32, aspect_ratio: f32, canvas_y: f32, image_y: u32) -> Self {
|
||||
let iso = Isometry3::face_towards(&pos, &(pos + dir), &up);
|
||||
Camera {
|
||||
matrix: iso,
|
||||
focal_length: focal_length,
|
||||
canvas_size: Vector2::new(canvas_x, canvas_x * aspect_ratio),
|
||||
image_size: Vector2::new(image_x, (image_x as f32 * aspect_ratio) as u32)
|
||||
canvas_size: Vector2::new(canvas_y * aspect_ratio, canvas_y),
|
||||
image_size: Vector2::new((image_y as f32 * aspect_ratio) as u32, image_y)
|
||||
}
|
||||
}
|
||||
|
||||
// Constructs a new camera from a position and viewing direction
|
||||
// (assuming the camera is oriented upright).
|
||||
pub fn new(pos: Point3<f32>, dir: Vector3<f32>,
|
||||
focal_length: f32, aspect_ratio: f32, canvas_x: f32, image_x: u32) -> Self
|
||||
{ Camera::new_(pos, dir, Vector3::y(), focal_length, aspect_ratio, canvas_x, image_x) }
|
||||
focal_length: f32, aspect_ratio: f32, canvas_y: f32, image_y: u32) -> Self
|
||||
{ Camera::new_(pos, dir, Vector3::y(), focal_length, aspect_ratio, canvas_y, image_y) }
|
||||
|
||||
pub fn pos(&self) -> Point3<f32> { Point3::from(self.matrix.translation.vector) }
|
||||
|
||||
|
|
|
@ -52,12 +52,13 @@ fn render(camera: &Camera, scene: &Scene, filename: &str) -> std::io::Result<()>
|
|||
|
||||
fn main() -> std::io::Result<()> {
|
||||
|
||||
let camera = Camera::new(Point3::new(0.0,1.0,0.0), Vector3::new(0.0,0.0,1.0), 1.0, 1.0, 2.0, 500);
|
||||
let camera = Camera::new(Point3::new(0.0,1.0,0.0), Vector3::new(0.0,0.0,1.0), 1.0, 16.0 / 9.0, 2.0, 720);
|
||||
|
||||
let scene = vec![
|
||||
Object::new(Plane::xz(|x, y| Color::new(y.sin(), x.cos(), 0.0))),
|
||||
Object::new(Plane::new(Point3::new(0.0, 2.0, 0.0), Vector3::z(), Vector3::x(), |x, y| Color::new(x.sin(), y.cos(), 0.0)))
|
||||
// Object::new(Sphere::new_solid(0.0, 0.0, 0.0, 3.0, Color::white()))
|
||||
Object::new(Plane::new(Point3::new(0.0, 0.0, -1.0), Vector3::x(), Vector3::z(),
|
||||
|x, y| Color::gray(y / 30.0)
|
||||
)),
|
||||
Object::new(Sphere::new(0.0, 1.0, 4.0, 1.0, |x, y| Color::new(0.0, x, y)))
|
||||
];
|
||||
|
||||
render(&camera, &scene, "out.ppm")
|
||||
|
|
|
@ -29,7 +29,7 @@ pub struct Object {
|
|||
}
|
||||
|
||||
impl Object {
|
||||
pub fn new<S: 'static + Surface>(surface: S) -> Self {
|
||||
pub fn new(surface: impl 'static + Surface) -> Self {
|
||||
Object { surface: Box::new(surface) }
|
||||
}
|
||||
|
||||
|
|
|
@ -6,10 +6,10 @@ use na::geometry::Point3;
|
|||
use crate::types::*;
|
||||
use super::Surface;
|
||||
|
||||
pub struct Triangle<'a> {
|
||||
pub vertex1: &'a Point3<f32>, // References to 3 vertices.
|
||||
pub vertex2: &'a Point3<f32>,
|
||||
pub vertex3: &'a Point3<f32>,
|
||||
pub struct Triangle {
|
||||
pub v1: usize, // Handles to 3 vertices.
|
||||
pub v2: usize,
|
||||
pub v3: usize,
|
||||
|
||||
area: f32, // Precalculated area for barycentric calculations.
|
||||
|
||||
|
@ -17,9 +17,9 @@ pub struct Triangle<'a> {
|
|||
// Uses barycentric coordinates as input.
|
||||
}
|
||||
|
||||
pub struct TriangleMesh<'a> {
|
||||
pub points: Vec<Box<Point3<f32>>>,
|
||||
pub tris: Vec<Triangle<'a>>
|
||||
pub struct TriangleMesh {
|
||||
pub points: Vec<Point3<f32>>,
|
||||
pub tris: Vec<Triangle>
|
||||
}
|
||||
|
||||
fn tri_area(a: &Point3<f32>, b: &Point3<f32>, c: &Point3<f32>) -> f32 {
|
||||
|
@ -27,48 +27,96 @@ fn tri_area(a: &Point3<f32>, b: &Point3<f32>, c: &Point3<f32>) -> f32 {
|
|||
prlg_area / 2.0
|
||||
}
|
||||
|
||||
impl<'a> Triangle<'a> {
|
||||
pub fn new<F: 'static>(vertex1: &'a Point3<f32>,
|
||||
vertex2: &'a Point3<f32>,
|
||||
vertex3: &'a Point3<f32>,
|
||||
texture: F) -> Self
|
||||
where F: Fn(f32, f32, f32) -> Color
|
||||
{
|
||||
Triangle {
|
||||
vertex1: vertex1,
|
||||
vertex2: vertex2,
|
||||
vertex3: vertex3,
|
||||
area: tri_area(vertex1, vertex2, vertex3),
|
||||
texture: Box::new(texture)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_solid(vertex1: &'a Point3<f32>,
|
||||
vertex2: &'a Point3<f32>,
|
||||
vertex3: &'a Point3<f32>, color: Color) -> Self
|
||||
{ Triangle::new(vertex1, vertex2, vertex3, move |_, _, _| color) }
|
||||
impl Triangle {
|
||||
fn vertex1<'a>(&self, vertices: &'a Vec<Point3<f32>>) -> &'a Point3<f32> { &vertices[self.v1] }
|
||||
fn vertex2<'a>(&self, vertices: &'a Vec<Point3<f32>>) -> &'a Point3<f32> { &vertices[self.v2] }
|
||||
fn vertex3<'a>(&self, vertices: &'a Vec<Point3<f32>>) -> &'a Point3<f32> { &vertices[self.v3] }
|
||||
|
||||
// Conversion of barycentric coordinates to
|
||||
// a point on the triangle.
|
||||
pub fn from_bary(&self, t: f32, u: f32, v: f32) -> Point3<f32> {
|
||||
Point::from(t * self.vertex1.coords + u * self.vertex2.coords + v * self.vertex3.coords)
|
||||
fn from_bary(&self, vertices: &Vec<Point3<f32>>, t: f32, u: f32, v: f32) -> Point3<f32> {
|
||||
Point::from(t * self.vertex1(vertices).coords + u * self.vertex2(vertices).coords + v * self.vertex3(vertices).coords)
|
||||
}
|
||||
|
||||
// Conversion of a point to barycentric coordinates.
|
||||
pub fn to_bary(&self, point: Point3<f32>) -> (f32, f32, f32) {
|
||||
let t = tri_area(self.vertex2, self.vertex3, &point) / self.area;
|
||||
let u = tri_area(self.vertex1, self.vertex3, &point) / self.area;
|
||||
let v = tri_area(self.vertex1, self.vertex2, &point) / self.area;
|
||||
fn to_bary(&self, vertices: &Vec<Point3<f32>>, point: Point3<f32>) -> (f32, f32, f32) {
|
||||
let t = tri_area(self.vertex2(vertices), self.vertex3(vertices), &point) / self.area;
|
||||
let u = tri_area(self.vertex1(vertices), self.vertex3(vertices), &point) / self.area;
|
||||
let v = tri_area(self.vertex1(vertices), self.vertex2(vertices), &point) / self.area;
|
||||
|
||||
(t, u, v)
|
||||
}
|
||||
|
||||
fn intersect(&self, vertices: &Vec<Point3<f32>>, ray: Ray) -> Option<f32> {
|
||||
let vect2_1 = self.vertex2(vertices) - self.vertex1(vertices);
|
||||
let vect3_1 = self.vertex3(vertices) - self.vertex1(vertices);
|
||||
|
||||
let p_vect = ray.direction.cross(&vect3_1);
|
||||
let det = p_vect.dot(&vect2_1);
|
||||
|
||||
if det.abs() < 1e-5 { return None; }
|
||||
|
||||
let t_vect = ray.origin - self.vertex1(vertices);
|
||||
let u = t_vect.dot(&p_vect) / det;
|
||||
|
||||
if u < 0.0 || u > 1.0 { return None; }
|
||||
|
||||
let q_vect = t_vect.cross(&vect2_1);
|
||||
let v = ray.direction.dot(&q_vect) / det;
|
||||
|
||||
if v < 0.0 || (u + v) > 1.0 { return None; }
|
||||
|
||||
let t = vect3_1.dot(&q_vect) / det;
|
||||
|
||||
// Convert from barycentric coordinates
|
||||
Some(distance(&ray.origin, &self.from_bary(vertices, t, u, v)))
|
||||
}
|
||||
|
||||
fn normal(&self, vertices: &Vec<Point3<f32>>, _point: Point3<f32>) -> Unit<Vector3<f32>> {
|
||||
Unit::new_normalize((self.vertex2(vertices) - self.vertex1(vertices)).cross(&(self.vertex3(vertices) - self.vertex1(vertices))))
|
||||
}
|
||||
|
||||
fn getcolor(&self, vertices: &Vec<Point3<f32>>, point: Point3<f32>) -> Color {
|
||||
// Converting back and forth between barycentric coordinates
|
||||
// like this is terrible, but it's necessary for this object to
|
||||
// match the interface the other objects use.
|
||||
let (t, u, v) = self.to_bary(vertices, point);
|
||||
|
||||
(*self.texture)(t, u, v)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TriangleMesh<'a> {
|
||||
pub fn new(points: Vec<Box<Point3<f32>>>, tris: Vec<Triangle<'a>>) -> Self {
|
||||
impl TriangleMesh {
|
||||
pub fn new(points: Vec<Point3<f32>>, tris: Vec<(usize, usize, usize, Box<dyn Fn(f32, f32, f32) -> Color>)>) -> Self {
|
||||
let triangles = tris.into_iter()
|
||||
.map(|(v1, v2, v3, f)| Triangle {
|
||||
v1: v1,
|
||||
v2: v2,
|
||||
v3: v3,
|
||||
area: tri_area(&points[v1], &points[v2], &points[v3]),
|
||||
texture: f
|
||||
}).collect();
|
||||
TriangleMesh {
|
||||
points: points,
|
||||
tris: tris
|
||||
tris: triangles
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_solid(points: Vec<Point3<f32>>, tris: Vec<(usize, usize, usize)>, color: Color) -> Self {
|
||||
let triangles = tris.into_iter()
|
||||
.map(|(v1, v2, v3)| Triangle {
|
||||
v1: v1,
|
||||
v2: v2,
|
||||
v3: v3,
|
||||
area: tri_area(&points[v1], &points[v2], &points[v3]),
|
||||
texture: Box::new(move |_, _, _| color)
|
||||
}).collect();
|
||||
TriangleMesh {
|
||||
points: points,
|
||||
tris: triangles
|
||||
}
|
||||
}
|
||||
|
||||
pub fn singleton<F: 'static>(vertex1: Point3<f32>, vertex2: Point3<f32>, vertex3: Point3<f32>, texture: F) -> Self
|
||||
where F: Fn(f32, f32, f32) -> Color
|
||||
{ TriangleMesh::new(vec![vertex1, vertex2, vertex3], vec![(0, 1, 2, Box::new(texture))]) }
|
||||
|
|
20
src/types.rs
20
src/types.rs
|
@ -48,22 +48,8 @@ impl Color {
|
|||
[red, green, blue]
|
||||
}
|
||||
|
||||
pub fn black() -> Self {
|
||||
Color {
|
||||
red: 0.0,
|
||||
green: 0.0,
|
||||
blue: 0.0,
|
||||
pub fn gray(brightness: f32) -> Self { Color::new(brightness, brightness, brightness) }
|
||||
|
||||
_private: ()
|
||||
}
|
||||
}
|
||||
pub fn white() -> Self {
|
||||
Color {
|
||||
red: 1.0,
|
||||
green: 1.0,
|
||||
blue: 1.0,
|
||||
|
||||
_private: ()
|
||||
}
|
||||
}
|
||||
pub fn black() -> Self { Color::gray(0.0) }
|
||||
pub fn white() -> Self { Color::gray(1.0) }
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue