This commit is contained in:
Michael Zhang 2023-03-22 19:21:35 -05:00
parent a84ee1724d
commit 46dad30da9
20 changed files with 223 additions and 39 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

View file

@ -0,0 +1,14 @@
eye 0 0 0
viewdir 0 0 -1
updir 0 1 0
hfov 60
imsize 512 256
bkgcolor 0.1 0.1 0.1
light -2 1 0 1 1 1 1
mtlcolor 0 1 0 1 1 1 0.2 0.6 0.2 20
v 0 1 -4
v -1 -1 -4
v 1 -1 -4
v 2 1 -6
f 1 2 3
f 1 3 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -0,0 +1,18 @@
eye 0 0 0
viewdir 0 0 -1
updir 0 1 0
hfov 60
imsize 512 256
bkgcolor 0.1 0.1 0.1
light -2 1 0 1 1 1 1
mtlcolor 0 0 1 1 1 1 0.2 0.6 0.2 20
v -1 1 -4
v -1 -1 -4
v 1 -1 -4
v 1 1 -4
vn -1 1 1
vn -1 -1 1
vn 1 -1 1
vn 1 1 1
f 1//1 2//2 3//3
f 1//1 3//3 4//4

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

View file

@ -0,0 +1,10 @@
eye 2 -6 1
viewdir -1 3 -0.5
updir 0 0 1
hfov 50
imsize 512 512
bkgcolor 0.5 0.7 0.9
light 0 1 -1 0 1 1 1
mtlcolor 0 1 0 1 1 1 0.2 0.8 0.1 20
texture earthtexture.ppm
sphere 0 0 0 2

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View file

@ -0,0 +1,19 @@
eye 0 0 0
viewdir 0 0 -1
updir 0 1 0
hfov 60
imsize 512 256
bkgcolor 0.1 0.1 0.1
light -2 1 0 1 1 1 1
mtlcolor 0 0 1 1 1 1 0.2 0.6 0.2 20
texture umn.ppm
v -1 1 -4
v -1 -1 -4
v 1 -1 -4
v 1 1 -4
vt 0 0
vt 0 1
vt 1 1
vt 1 0
f 1/1 2/2 3/3
f 1/1 3/3 4/4

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View file

@ -0,0 +1,25 @@
eye 0 0 0
viewdir 0 0 -1
updir 0 1 0
hfov 60
imsize 512 256
bkgcolor 0.1 0.1 0.1
light -2 1 0 1 1 1 1
mtlcolor 0 0 1 1 1 1 0.2 0.6 0.2 20
texture umn.ppm
v -1 1 -4
v -1 -1 -4
v 1 -1 -4
v 1 1 -4
vn -1 1 1
vn -1 -1 1
vn 1 -1 1
vn 1 1 1
vt 0 0
vt 0 1
vt 1 1
vt 1 0
f 1/1/1 2/2/2 3/3/3
f 1/1/1 3/3/3 4/4/4

Binary file not shown.

After

Width:  |  Height:  |  Size: 640 KiB

View file

@ -0,0 +1,56 @@
eye 12.5 5 2.5
viewdir -2 -0.5 2
updir 0 1 0
hfov 60
imsize 900 600
bkgcolor 0.5 0.7 0.9
light 1 -1 1 0 1 1 1
mtlcolor 0 1 0 1 1 1 0.2 0.8 0 20
v 10 0 5
v -10 0 5
v -10 0 25
v 10 0 25
v 5 0 12.5
v -5 0 12.5
v -5 5 12.5
v 5 5 12.5
v 5 0 17.5
v -5 0 17.5
v -5 5 17.5
v 5 5 17.5
v 5 7.5 15
v -5 7.5 15
v 5 4.5 12
v -5 4.5 12
v 5 4.5 18
v -5 4.5 18
vt 0 0
vt 0 1
vt 1 1
vt 1 0
vt 2 0
vt 2 1
vt 0.5 0
vt 4 0
vt 4 1
texture grass.ppm
f 1/2 2/3 3/4
f 1/2 3/4 4/1
texture wood.ppm
f 5/2 6/6 7/5
f 5/2 7/5 8/1
f 9/2 11/5 10/6
f 9/2 12/1 11/5
f 6/2 10/3 11/4
f 6/2 11/4 7/1
f 5/3 12/1 9/2
f 5/3 8/4 12/1
f 7/2 11/3 14/7
f 8/3 13/7 12/2
texture redwood.ppm
f 13/1 15/2 16/9
f 13/1 16/9 14/8
f 13/8 14/1 18/2
f 13/8 18/2 17/9
texture soccerball.ppm
sphere -2.5 0.5 9 0.5

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View file

@ -0,0 +1,20 @@
eye 0 0 0
viewdir 0 0 -1
updir 0 1 0
hfov 60
imsize 512 256
bkgcolor 0.1 0.1 0.1
light -2 1 0 1 1 1 1
mtlcolor 1 1 1 1 1 1 0.2 0.6 0.2 20 1 0
bump normalmap.ppm
sphere -1.6 0 -4 0.5
v -1 1 -4
v -1 -1 -4
v 1 -1 -4
v 1 1 -4
vt 0 0
vt 0 1
vt 1 1
vt 1 0
f 1/1 2/2 3/3
f 1/1 3/3 4/4

View file

@ -0,0 +1,2 @@
#! /bin/sh
PROGRAM_NAME="raytracer1c"; echo "-------- Running Test1.txt --------"; ./$PROGRAM_NAME Test1.txt; echo "-------- Running Test2.txt --------";./$PROGRAM_NAME Test2.txt; echo "-------- Running Test3.txt --------";./$PROGRAM_NAME Test3.txt; echo "-------- Running Test4.txt --------";./$PROGRAM_NAME Test4.txt; echo "-------- Running Test5.txt --------";./$PROGRAM_NAME Test5.txt; echo "-------- Running Test6.txt --------";./$PROGRAM_NAME Test6.txt; echo "-------- Running TestE.txt --------";./$PROGRAM_NAME TestE.txt;

View file

@ -4,7 +4,7 @@ extern crate tracing;
use std::fs::File; use std::fs::File;
use std::path::PathBuf; use std::path::PathBuf;
use anyhow::Result; use anyhow::{Context, Result};
use assignment_1c::image::Image; use assignment_1c::image::Image;
use assignment_1c::ray::Ray; use assignment_1c::ray::Ray;
use assignment_1c::scene::Scene; use assignment_1c::scene::Scene;
@ -112,9 +112,9 @@ fn main() -> Result<()> {
Ok(match earliest_intersection { Ok(match earliest_intersection {
// Take the object's material color // Take the object's material color
Some((obj_idx, intersection_context, object)) => { Some((obj_idx, intersection_context, object)) => scene
scene.compute_pixel_color(obj_idx, object, intersection_context)? .compute_pixel_color(obj_idx, object, intersection_context)
} .context("Could not compute pixel color.")?,
// There was no intersection, so this should default to the scene's // There was no intersection, so this should default to the scene's
// background color // background color

View file

@ -43,7 +43,7 @@ impl Scene {
let texture = match self.textures.get(texture_idx) { let texture = match self.textures.get(texture_idx) {
Some(v) => v, Some(v) => v,
None => bail!("Texture index not found."), None => bail!("Texture index {texture_idx} not found."),
}; };
texture.pixel_at(u, v) texture.pixel_at(u, v)

View file

@ -4,7 +4,7 @@ use std::path::Path;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use itertools::Itertools; use itertools::Itertools;
use nalgebra::Vector3; use nalgebra::{Vector2, Vector3};
use crate::{ use crate::{
image::{Color, Image}, image::{Color, Image},
@ -13,7 +13,7 @@ use crate::{
data::{Attenuation, Light, LightKind, Material}, data::{Attenuation, Light, LightKind, Material},
object::{Object, ObjectKind}, object::{Object, ObjectKind},
sphere::Sphere, sphere::Sphere,
texture::{Texture, NormalMap}, texture::Texture,
triangle::Triangle, triangle::Triangle,
Scene, Scene,
}, },
@ -209,6 +209,9 @@ impl Scene {
// vn nx ny nz // vn nx ny nz
"vn" => scene.vertex_normals.push(r!(Vector)), "vn" => scene.vertex_normals.push(r!(Vector)),
// vt u v
"vt" => scene.texture_vertices.push(r!(Vector2<f64>)),
// f v1 v2 v3 // f v1 v2 v3
// f v1//n1 v2//n2 v3//n3 // f v1//n1 v2//n2 v3//n3
"f" => { "f" => {
@ -230,7 +233,7 @@ impl Scene {
let textures = match textures.iter().filter(|o| o.is_some()).count() { let textures = match textures.iter().filter(|o| o.is_some()).count() {
0 => None, 0 => None,
n if n == vs.len() => Some(textures.map(|o| o.unwrap())), n if n == vs.len() => Some(textures.map(|o| o.unwrap())),
_ => bail!("Cannot mix and match having a normal index"), _ => bail!("Cannot mix and match having a texture index"),
}; };
let triangle = Triangle { let triangle = Triangle {
@ -256,7 +259,7 @@ impl Scene {
texture_idx = Some(idx); texture_idx = Some(idx);
let image = Image::from_file(path)?; let image = Image::from_file(path)?;
let texture = Texture::new(image); let texture = Texture::new(image, false);
scene.textures.push(texture); scene.textures.push(texture);
} }
@ -271,8 +274,8 @@ impl Scene {
texture_idx = Some(idx); texture_idx = Some(idx);
let image = Image::from_file(path)?; let image = Image::from_file(path)?;
let normal_map = NormalMap::new(image); let normal_map = Texture::new(image, true);
scene.normal_maps.push(normal_map); scene.textures.push(normal_map);
} }
_ => bail!("Unknown keyword {keyword}"), _ => bail!("Unknown keyword {keyword}"),
@ -332,6 +335,25 @@ macro_rules! impl_construct {
impl_construct!(f64); impl_construct!(f64);
impl_construct!(usize); impl_construct!(usize);
impl Construct for Vector2<f64> {
type Args = ();
fn construct<'a, I>(it: &mut I, _: Self::Args) -> Result<Self>
where
I: Iterator<Item = &'a str>,
{
let (x, y) = match it.next_tuple() {
Some(v) => v,
None => bail!("Expected 2 values"),
};
let x: f64 = x.parse()?;
let y: f64 = y.parse()?;
Ok(Vector2::new(x, y))
}
}
impl Construct for Vector3<f64> { impl Construct for Vector3<f64> {
type Args = (); type Args = ();

View file

@ -7,12 +7,14 @@ pub mod sphere;
pub mod texture; pub mod texture;
pub mod triangle; pub mod triangle;
use nalgebra::Vector2;
use crate::image::Color; use crate::image::Color;
use crate::{Point, Point2, Vector}; use crate::{Point, Point2, Vector};
use self::data::{Attenuation, DepthCueing, Light, Material}; use self::data::{Attenuation, DepthCueing, Light, Material};
use self::object::Object; use self::object::Object;
use self::texture::{Texture, NormalMap}; use self::texture::{Texture};
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Scene { pub struct Scene {
@ -40,7 +42,7 @@ pub struct Scene {
pub textures: Vec<Texture>, pub textures: Vec<Texture>,
/// List of normal maps (Extra credit) /// List of normal maps (Extra credit)
pub normal_maps: Vec<NormalMap>, pub normal_maps: Vec<Texture>,
/// Coordinates into a texture image /// Coordinates into a texture image
pub texture_vertices: Vec<Point2>, pub texture_vertices: Vec<Point2>,

View file

@ -4,17 +4,33 @@ use crate::{
}; };
#[derive(Debug)] #[derive(Debug)]
pub struct Texture(Image); pub struct Texture {
image: Image,
is_normal_map: bool,
}
impl Texture { impl Texture {
pub fn new(image: Image) -> Self { pub fn new(image: Image, is_normal_map: bool) -> Self {
Self(image) Self {
image,
is_normal_map,
}
} }
pub fn pixel_at_exact(&self, x: usize, y: usize) -> Color { pub fn pixel_at_exact(&self, x: usize, y: usize) -> Color {
// TODO: Debug asserts? // TODO: Debug asserts?
self.0.data[y * self.0.width + x] let x = match x {
n if n < self.image.width => n,
_ => self.image.width - 1,
};
let y = match y {
n if n < self.image.height => n,
_ => self.image.height - 1,
};
self.image.data[y * self.image.width + x]
} }
/// Returns a pixel at the given coordinate. For non-lattice coordinates, /// Returns a pixel at the given coordinate. For non-lattice coordinates,
@ -24,8 +40,8 @@ impl Texture {
debug_assert!(0.0 <= v && v <= 1.0, "u must be between 0 and 1"); debug_assert!(0.0 <= v && v <= 1.0, "u must be between 0 and 1");
// Slide 121 // Slide 121
let x = u * (self.0.width - 1) as f64; let x = u * (self.image.width - 1) as f64;
let y = v * (self.0.height - 1) as f64; let y = v * (self.image.height - 1) as f64;
let i = x.floor(); let i = x.floor();
let j = y.floor(); let j = y.floor();
@ -42,23 +58,3 @@ impl Texture {
+ (alpha) * (beta) * self.pixel_at_exact(i + 1, j + 1) + (alpha) * (beta) * self.pixel_at_exact(i + 1, j + 1)
} }
} }
#[derive(Debug)]
pub struct NormalMap(Image);
impl NormalMap {
pub fn new(image: Image) -> Self {
Self(image)
}
pub fn normal_vector_at_exact(&self, x: usize, y: usize) -> Vector {
let vec = self.0.data[y * self.0.width + x];
// So, according to the instructions, this should actually be a value
// between -1 and 1. However, we're reading this in through an image.
// I'm just going to do the lazy thing here (which theoretically
// actually saves cycles) by only doing the transformation when loading
// out of the image
vec.map(|value| 2.0 * value / 255.0 - 1.0)
}
}