Implement textured coordinates
This commit is contained in:
parent
26ddd8d236
commit
a52863fe6c
4 changed files with 90 additions and 21 deletions
|
@ -34,7 +34,7 @@ Due: Friday March 3rd
|
|||
color in the Phong illumination model when it is evaluated at that point.
|
||||
(25 pts)
|
||||
|
||||
- [ ] The program is capable of rendering textured triangles. The texture
|
||||
- [x] The program is capable of rendering textured triangles. The texture
|
||||
coordinate at the ray/triangle intersection point is correctly
|
||||
interpolated from the texture coordinates defined at each of the three
|
||||
triangle vertices. The interpolated texture coordinate is used to retrieve
|
||||
|
|
|
@ -37,7 +37,9 @@ impl Scene {
|
|||
|
||||
let diffuse_color = match object.texture_idx {
|
||||
Some(texture_idx) => {
|
||||
let (u, v) = object.kind.get_texture_coord(&intersection_context)?;
|
||||
let (u, v) = object
|
||||
.kind
|
||||
.get_texture_coord(&self, &intersection_context)?;
|
||||
|
||||
let texture = match self.textures.get(texture_idx) {
|
||||
Some(v) => v,
|
||||
|
|
|
@ -49,12 +49,13 @@ impl ObjectKind {
|
|||
/// the intersection point
|
||||
pub fn get_texture_coord(
|
||||
&self,
|
||||
scene: &Scene,
|
||||
ctx: &IntersectionContext,
|
||||
) -> Result<(f64, f64)> {
|
||||
match self {
|
||||
ObjectKind::Sphere(sphere) => sphere.get_texture_coord(ctx),
|
||||
ObjectKind::Cylinder(cylinder) => todo!(),
|
||||
ObjectKind::Triangle(triangle) => todo!(),
|
||||
ObjectKind::Triangle(triangle) => triangle.get_texture_coord(scene, ctx),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ use ordered_float::NotNan;
|
|||
|
||||
use crate::ray::Ray;
|
||||
use crate::utils::{cross, dot};
|
||||
use crate::{Point, Vector};
|
||||
|
||||
use super::illumination::IntersectionContext;
|
||||
use super::Scene;
|
||||
|
@ -11,7 +12,11 @@ use super::Scene;
|
|||
#[derive(Debug)]
|
||||
pub struct Triangle {
|
||||
pub vertices: Vector3<usize>,
|
||||
|
||||
/// Indexes into the scene's normal coordinates list
|
||||
pub normals: Option<Vector3<usize>>,
|
||||
|
||||
/// Indexes into the scene's texture coordinates list
|
||||
pub textures: Option<Vector3<usize>>,
|
||||
}
|
||||
|
||||
|
@ -21,17 +26,13 @@ impl Triangle {
|
|||
scene: &Scene,
|
||||
ray: &Ray,
|
||||
) -> Result<Option<IntersectionContext>> {
|
||||
let p0 = scene.triangle_vertices[self.vertices.x];
|
||||
let p1 = scene.triangle_vertices[self.vertices.y];
|
||||
let p2 = scene.triangle_vertices[self.vertices.z];
|
||||
let (p0, e1, e2) = self.basis_vectors(scene);
|
||||
|
||||
// Solve for the plane equation coefficients A, B, C, D such that:
|
||||
//
|
||||
// $$
|
||||
// Ax + By + Cz + D = 0
|
||||
// $$
|
||||
let e1 = p1 - p0;
|
||||
let e2 = p2 - p0;
|
||||
let n = cross(e1, e2);
|
||||
let a = n.x;
|
||||
let b = n.y;
|
||||
|
@ -63,21 +64,10 @@ impl Triangle {
|
|||
// p = p0 + beta * e1 + gamma * e2
|
||||
// Using the whack linear algebra approach derived on slide 57
|
||||
let ep = point - p0;
|
||||
let d = Matrix2::new(dot(e1, e1), dot(e1, e2), dot(e2, e1), dot(e2, e2));
|
||||
let p = Vector2::new(dot(e1, ep), dot(e2, ep));
|
||||
|
||||
let d_inv = match d.try_inverse() {
|
||||
Some(v) => v,
|
||||
// TODO: Whack
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
||||
let sol = d_inv * p;
|
||||
let beta = sol.x;
|
||||
let gamma = sol.y;
|
||||
|
||||
// Slide 46
|
||||
let alpha = 1.0 - beta - gamma;
|
||||
let (alpha, beta, gamma) =
|
||||
self.compute_barycentric_coordinates(scene, p)?;
|
||||
|
||||
// Each of alpha, beta, and gamma must be between 0 and 1
|
||||
if ![alpha, beta, gamma].into_iter().all(|v| 0.0 < v && v < 1.0) {
|
||||
|
@ -103,4 +93,80 @@ impl Triangle {
|
|||
normal,
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn get_texture_coord(
|
||||
&self,
|
||||
scene: &Scene,
|
||||
ctx: &IntersectionContext,
|
||||
) -> Result<(f64, f64)> {
|
||||
let texture_coordinates = match self.textures {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
bail!("Textured triangle requested without providing coordinates")
|
||||
}
|
||||
};
|
||||
|
||||
let p0 = scene.texture_vertices[texture_coordinates.x];
|
||||
let p1 = scene.texture_vertices[texture_coordinates.y];
|
||||
let p2 = scene.texture_vertices[texture_coordinates.z];
|
||||
|
||||
let p = self.convert_point(scene, ctx.point);
|
||||
let (alpha, beta, gamma) =
|
||||
self.compute_barycentric_coordinates(scene, p)?;
|
||||
|
||||
let u = alpha * p0.x + beta * p1.x + gamma * p2.x;
|
||||
let v = alpha * p0.y + beta * p1.y + gamma * p2.y;
|
||||
|
||||
Ok((u, v))
|
||||
}
|
||||
|
||||
fn convert_point(&self, scene: &Scene, point: Point) -> Vector2<f64> {
|
||||
let (p0, e1, e2) = self.basis_vectors(scene);
|
||||
|
||||
let ep = point - p0;
|
||||
Vector2::new(dot(e1, ep), dot(e2, ep))
|
||||
}
|
||||
|
||||
/// Fetch the corners of the triangles from the scene
|
||||
#[inline]
|
||||
fn corner_coordinates(&self, scene: &Scene) -> (Point, Point, Point) {
|
||||
let p0 = scene.triangle_vertices[self.vertices.x];
|
||||
let p1 = scene.triangle_vertices[self.vertices.y];
|
||||
let p2 = scene.triangle_vertices[self.vertices.z];
|
||||
|
||||
(p0, p1, p2)
|
||||
}
|
||||
|
||||
/// Get the new basis vectors using p0 as the origin.
|
||||
#[inline]
|
||||
fn basis_vectors(&self, scene: &Scene) -> (Vector, Vector, Vector) {
|
||||
let (p0, p1, p2) = self.corner_coordinates(scene);
|
||||
let e1 = p1 - p0;
|
||||
let e2 = p2 - p0;
|
||||
(p0, e1, e2)
|
||||
}
|
||||
|
||||
fn compute_barycentric_coordinates(
|
||||
&self,
|
||||
scene: &Scene,
|
||||
p: Vector2<f64>,
|
||||
) -> Result<(f64, f64, f64)> {
|
||||
let (_, e1, e2) = self.basis_vectors(scene);
|
||||
let d = Matrix2::new(dot(e1, e1), dot(e1, e2), dot(e2, e1), dot(e2, e2));
|
||||
|
||||
let d_inv = match d.try_inverse() {
|
||||
Some(v) => v,
|
||||
// TODO: Whack
|
||||
None => bail!("No inverse..."),
|
||||
};
|
||||
|
||||
let sol = d_inv * p;
|
||||
let beta = sol.x;
|
||||
let gamma = sol.y;
|
||||
|
||||
// Slide 46
|
||||
let alpha = 1.0 - beta - gamma;
|
||||
|
||||
Ok((alpha, beta, gamma))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue