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.
|
color in the Phong illumination model when it is evaluated at that point.
|
||||||
(25 pts)
|
(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
|
coordinate at the ray/triangle intersection point is correctly
|
||||||
interpolated from the texture coordinates defined at each of the three
|
interpolated from the texture coordinates defined at each of the three
|
||||||
triangle vertices. The interpolated texture coordinate is used to retrieve
|
triangle vertices. The interpolated texture coordinate is used to retrieve
|
||||||
|
|
|
@ -37,7 +37,9 @@ impl Scene {
|
||||||
|
|
||||||
let diffuse_color = match object.texture_idx {
|
let diffuse_color = match object.texture_idx {
|
||||||
Some(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) {
|
let texture = match self.textures.get(texture_idx) {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
|
|
|
@ -49,12 +49,13 @@ impl ObjectKind {
|
||||||
/// the intersection point
|
/// the intersection point
|
||||||
pub fn get_texture_coord(
|
pub fn get_texture_coord(
|
||||||
&self,
|
&self,
|
||||||
|
scene: &Scene,
|
||||||
ctx: &IntersectionContext,
|
ctx: &IntersectionContext,
|
||||||
) -> Result<(f64, f64)> {
|
) -> Result<(f64, f64)> {
|
||||||
match self {
|
match self {
|
||||||
ObjectKind::Sphere(sphere) => sphere.get_texture_coord(ctx),
|
ObjectKind::Sphere(sphere) => sphere.get_texture_coord(ctx),
|
||||||
ObjectKind::Cylinder(cylinder) => todo!(),
|
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::ray::Ray;
|
||||||
use crate::utils::{cross, dot};
|
use crate::utils::{cross, dot};
|
||||||
|
use crate::{Point, Vector};
|
||||||
|
|
||||||
use super::illumination::IntersectionContext;
|
use super::illumination::IntersectionContext;
|
||||||
use super::Scene;
|
use super::Scene;
|
||||||
|
@ -11,7 +12,11 @@ use super::Scene;
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Triangle {
|
pub struct Triangle {
|
||||||
pub vertices: Vector3<usize>,
|
pub vertices: Vector3<usize>,
|
||||||
|
|
||||||
|
/// Indexes into the scene's normal coordinates list
|
||||||
pub normals: Option<Vector3<usize>>,
|
pub normals: Option<Vector3<usize>>,
|
||||||
|
|
||||||
|
/// Indexes into the scene's texture coordinates list
|
||||||
pub textures: Option<Vector3<usize>>,
|
pub textures: Option<Vector3<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,17 +26,13 @@ impl Triangle {
|
||||||
scene: &Scene,
|
scene: &Scene,
|
||||||
ray: &Ray,
|
ray: &Ray,
|
||||||
) -> Result<Option<IntersectionContext>> {
|
) -> Result<Option<IntersectionContext>> {
|
||||||
let p0 = scene.triangle_vertices[self.vertices.x];
|
let (p0, e1, e2) = self.basis_vectors(scene);
|
||||||
let p1 = scene.triangle_vertices[self.vertices.y];
|
|
||||||
let p2 = scene.triangle_vertices[self.vertices.z];
|
|
||||||
|
|
||||||
// Solve for the plane equation coefficients A, B, C, D such that:
|
// Solve for the plane equation coefficients A, B, C, D such that:
|
||||||
//
|
//
|
||||||
// $$
|
// $$
|
||||||
// Ax + By + Cz + D = 0
|
// Ax + By + Cz + D = 0
|
||||||
// $$
|
// $$
|
||||||
let e1 = p1 - p0;
|
|
||||||
let e2 = p2 - p0;
|
|
||||||
let n = cross(e1, e2);
|
let n = cross(e1, e2);
|
||||||
let a = n.x;
|
let a = n.x;
|
||||||
let b = n.y;
|
let b = n.y;
|
||||||
|
@ -63,21 +64,10 @@ impl Triangle {
|
||||||
// p = p0 + beta * e1 + gamma * e2
|
// p = p0 + beta * e1 + gamma * e2
|
||||||
// Using the whack linear algebra approach derived on slide 57
|
// Using the whack linear algebra approach derived on slide 57
|
||||||
let ep = point - p0;
|
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 p = Vector2::new(dot(e1, ep), dot(e2, ep));
|
||||||
|
|
||||||
let d_inv = match d.try_inverse() {
|
let (alpha, beta, gamma) =
|
||||||
Some(v) => v,
|
self.compute_barycentric_coordinates(scene, p)?;
|
||||||
// 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;
|
|
||||||
|
|
||||||
// Each of alpha, beta, and gamma must be between 0 and 1
|
// 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) {
|
if ![alpha, beta, gamma].into_iter().all(|v| 0.0 < v && v < 1.0) {
|
||||||
|
@ -103,4 +93,80 @@ impl Triangle {
|
||||||
normal,
|
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