Fix x and y swapped
This commit is contained in:
parent
d737124aa1
commit
3b04a7c494
5 changed files with 48 additions and 29 deletions
|
@ -2,7 +2,25 @@ use std::io::{Result, Write};
|
|||
|
||||
/// A 24-bit pixel represented by a red, green, and blue value.
|
||||
#[derive(Clone, Copy, Default, Debug)]
|
||||
pub struct Pixel(pub u8, pub u8, pub u8);
|
||||
pub struct Color {
|
||||
pub red: u8,
|
||||
pub green: u8,
|
||||
pub blue: u8,
|
||||
}
|
||||
|
||||
impl Color {
|
||||
pub fn new(r: u8, g: u8, b: u8) -> Self {
|
||||
Color {
|
||||
red: r,
|
||||
green: g,
|
||||
blue: b,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_01_float(r: f64, g: f64, b: f64) -> Self {
|
||||
Color::new((r * 256.0) as u8, (g * 256.0) as u8, (b * 256.0) as u8)
|
||||
}
|
||||
}
|
||||
|
||||
/// A representation of an image
|
||||
pub struct Image {
|
||||
|
@ -13,7 +31,7 @@ pub struct Image {
|
|||
pub(crate) height: usize,
|
||||
|
||||
/// Pixel data in row-major form.
|
||||
pub(crate) data: Vec<Pixel>,
|
||||
pub(crate) data: Vec<Color>,
|
||||
}
|
||||
|
||||
impl Image {
|
||||
|
@ -24,8 +42,10 @@ impl Image {
|
|||
w.write_all(header.as_bytes())?;
|
||||
|
||||
// Pixel data
|
||||
assert_eq!(self.data.len(), self.width * self.height);
|
||||
|
||||
for pixel in self.data.iter() {
|
||||
let Pixel(red, green, blue) = pixel;
|
||||
let Color { red, green, blue } = pixel;
|
||||
let pixel = format!("{red} {green} {blue}\n");
|
||||
w.write_all(pixel.as_bytes())?;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ use std::{fs::File, io::Read, path::Path};
|
|||
use anyhow::Result;
|
||||
|
||||
use crate::{
|
||||
image::Color,
|
||||
scene_data::{Object, Scene, Sphere},
|
||||
vec3::Vec3,
|
||||
};
|
||||
|
@ -48,18 +49,25 @@ pub fn parse_input_file(path: impl AsRef<Path>) -> Result<Scene> {
|
|||
Ok(Vec3::new(parts[0], parts[1], parts[2]))
|
||||
};
|
||||
|
||||
let read_color = || {
|
||||
if parts.len() < 3 {
|
||||
bail!("Color requires 3 components.");
|
||||
}
|
||||
Ok(Color::from_01_float(parts[0], parts[1], parts[2]))
|
||||
};
|
||||
|
||||
match keyword {
|
||||
"eye" => scene.eye_pos = read_vec3()?,
|
||||
"viewdir" => scene.view_dir = read_vec3()?,
|
||||
"updir" => scene.up_dir = read_vec3()?,
|
||||
|
||||
"hfov" => scene.hfov = parts[0],
|
||||
"bkgcolor" => scene.bkg_color = read_vec3()?,
|
||||
"bkgcolor" => scene.bkg_color = read_color()?,
|
||||
|
||||
"mtlcolor" => {
|
||||
let idx = scene.material_colors.len();
|
||||
material_color = Some(idx);
|
||||
scene.material_colors.push(read_vec3()?);
|
||||
scene.material_colors.push(read_color()?);
|
||||
}
|
||||
|
||||
"sphere" => scene.objects.push(Object::Sphere(Sphere {
|
||||
|
|
|
@ -15,7 +15,9 @@ use anyhow::Result;
|
|||
use clap::Parser;
|
||||
use itertools::Itertools;
|
||||
use ordered_float::NotNan;
|
||||
use rayon::prelude::{IntoParallelIterator, ParallelIterator};
|
||||
use rayon::prelude::{
|
||||
IndexedParallelIterator, IntoParallelIterator, ParallelIterator,
|
||||
};
|
||||
|
||||
use crate::image::Image;
|
||||
use crate::input_file::parse_input_file;
|
||||
|
@ -24,7 +26,7 @@ use crate::scene_data::Object;
|
|||
use crate::vec3::Vec3;
|
||||
use crate::view::Rect;
|
||||
|
||||
const ARBITRARY_D: f64 = 1.0;
|
||||
const ARBITRARY_D: f64 = 2.0;
|
||||
|
||||
/// Simple raycaster.
|
||||
#[derive(Parser)]
|
||||
|
@ -74,7 +76,6 @@ fn main() -> Result<()> {
|
|||
let viewing_height = viewing_width / aspect_ratio;
|
||||
|
||||
// Compute viewing window corners
|
||||
// TODO: See slide 101
|
||||
let n = scene.view_dir.unit();
|
||||
#[rustfmt::skip] // Otherwise this line wraps over
|
||||
let view_window = Rect {
|
||||
|
@ -103,14 +104,14 @@ fn main() -> Result<()> {
|
|||
};
|
||||
|
||||
// This is an L because par_bridge is unordered
|
||||
let pixels = (0..scene.image_width)
|
||||
.cartesian_product(0..scene.image_height)
|
||||
let pixels = (0..scene.image_height)
|
||||
.cartesian_product(0..scene.image_width)
|
||||
.collect_vec();
|
||||
|
||||
// Loop through every single pixel of the output file
|
||||
let pixels = pixels
|
||||
.into_par_iter()
|
||||
.map(|(px, py)| {
|
||||
.map(|(py, px)| {
|
||||
let pixel_in_space = translate_pixel(px, py);
|
||||
let ray = Ray::from_endpoints(scene.eye_pos, pixel_in_space);
|
||||
|
||||
|
@ -130,12 +131,12 @@ fn main() -> Result<()> {
|
|||
|
||||
let pixel_color = match earliest_intersection {
|
||||
Some((_, sphere)) => scene.material_colors[sphere.material],
|
||||
// There was no intersection, so this should default to the background
|
||||
// color
|
||||
// There was no intersection, so this should default to the scene's
|
||||
// background color
|
||||
None => scene.bkg_color,
|
||||
};
|
||||
|
||||
pixel_color.to_pixel()
|
||||
pixel_color
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::vec3::Vec3;
|
||||
use crate::{image::Color, vec3::Vec3};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Sphere {
|
||||
|
@ -33,8 +33,8 @@ pub struct Scene {
|
|||
pub image_height: usize,
|
||||
|
||||
/// Background color
|
||||
pub bkg_color: Vec3,
|
||||
pub bkg_color: Color,
|
||||
|
||||
pub material_colors: Vec<Vec3>,
|
||||
pub material_colors: Vec<Color>,
|
||||
pub objects: Vec<Object>,
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use std::ops::{Add, Div, Mul, Sub};
|
||||
use std::fmt;
|
||||
use std::ops::{Add, Div, Mul, Sub};
|
||||
|
||||
use num::Float;
|
||||
|
||||
use crate::image::Pixel;
|
||||
use crate::image::Color;
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
|
||||
pub struct Vec3<T = f64> {
|
||||
|
@ -54,16 +54,6 @@ impl<T: Float> Vec3<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Vec3<f64> {
|
||||
/// Convert into an RGB color
|
||||
pub fn to_pixel(&self) -> Pixel {
|
||||
let r = (self.x * 256.0) as u8;
|
||||
let g = (self.y * 256.0) as u8;
|
||||
let b = (self.z * 256.0) as u8;
|
||||
Pixel(r, g, b)
|
||||
}
|
||||
}
|
||||
|
||||
/// Vector addition
|
||||
impl<T> Add<Vec3<T>> for Vec3<T>
|
||||
where
|
||||
|
|
Loading…
Reference in a new issue