slight refactor
This commit is contained in:
parent
0000032041
commit
00000330fe
6 changed files with 188 additions and 161 deletions
|
@ -4,11 +4,15 @@ viewdir 0 0.1 -1
|
|||
hfov 90
|
||||
updir 0 1 0
|
||||
bkgcolor 0.1 0.1 0.1
|
||||
|
||||
light -1 -1 -1 0 0.9 0.5 0.05
|
||||
|
||||
mtlcolor 0 1 0 1 1 1 0.6 0.2 0.2 10
|
||||
sphere 0 1.5 -4 1
|
||||
|
||||
mtlcolor 0 1 0 1 1 1 0.1 0.8 0.2 10
|
||||
sphere -1.275 -0.75 -4 1
|
||||
|
||||
mtlcolor 0 1 0 1 1 1 0.1 0.2 0.8 10
|
||||
sphere 1.275 -0.75 -4 1
|
||||
|
||||
|
|
|
@ -1,138 +0,0 @@
|
|||
use std::{fs::File, io::Read, path::Path};
|
||||
|
||||
use anyhow::Result;
|
||||
use nalgebra::Vector3;
|
||||
|
||||
use crate::{
|
||||
image::Color,
|
||||
scene::{
|
||||
cylinder::Cylinder,
|
||||
data::{Light, LightKind, Material, Object, Scene},
|
||||
sphere::Sphere,
|
||||
},
|
||||
};
|
||||
|
||||
/// Parse the input file into a scene
|
||||
pub fn parse_input_file(path: impl AsRef<Path>) -> Result<Scene> {
|
||||
let contents = {
|
||||
let mut contents = String::new();
|
||||
let mut file = File::open(path.as_ref())?;
|
||||
file.read_to_string(&mut contents)?;
|
||||
contents
|
||||
};
|
||||
|
||||
let mut scene = Scene::default();
|
||||
let mut material_color = None;
|
||||
|
||||
for line in contents.lines() {
|
||||
let mut parts = line.split_whitespace();
|
||||
let keyword = match parts.next() {
|
||||
Some(v) => v,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
if keyword == "imsize" {
|
||||
let parts = parts
|
||||
.map(|s| s.parse::<usize>().map_err(|e| e.into()))
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
if let [width, height] = parts[..] {
|
||||
scene.image_width = width;
|
||||
scene.image_height = height;
|
||||
}
|
||||
} else if keyword == "projection" {
|
||||
if let Some("parallel") = parts.next() {
|
||||
scene.parallel_projection = true;
|
||||
}
|
||||
}
|
||||
// Do float parsing instead
|
||||
else {
|
||||
let parts = parts
|
||||
.map(|s| s.parse::<f64>().map_err(|e| e.into()))
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
let read_vec3 = |start: usize| {
|
||||
if parts.len() < start + 3 {
|
||||
bail!("Vec3 requires 3 components.");
|
||||
}
|
||||
Ok(Vector3::new(
|
||||
parts[start],
|
||||
parts[start + 1],
|
||||
parts[start + 2],
|
||||
))
|
||||
};
|
||||
|
||||
match keyword {
|
||||
"eye" => scene.eye_pos = read_vec3(0)?,
|
||||
"viewdir" => scene.view_dir = read_vec3(0)?,
|
||||
"updir" => scene.up_dir = read_vec3(0)?,
|
||||
|
||||
"hfov" => scene.hfov = parts[0],
|
||||
"bkgcolor" => scene.bkg_color = read_vec3(0)?,
|
||||
|
||||
"light" => {
|
||||
let kind = match parts[3] as usize {
|
||||
0 => LightKind::Directional {
|
||||
direction: read_vec3(0)?,
|
||||
},
|
||||
1 => LightKind::Point {
|
||||
location: read_vec3(0)?,
|
||||
},
|
||||
_ => bail!("Invalid w"),
|
||||
};
|
||||
let light = Light {
|
||||
kind,
|
||||
color: read_vec3(4)?,
|
||||
};
|
||||
scene.lights.push(light);
|
||||
}
|
||||
|
||||
// mtlcolor Odr Odg Odb Osr Osg Osb ka kd ks n
|
||||
"mtlcolor" => {
|
||||
let diffuse_color = read_vec3(0)?;
|
||||
let specular_color = read_vec3(3)?;
|
||||
|
||||
let material = Material {
|
||||
diffuse_color,
|
||||
specular_color,
|
||||
k_a: parts[6],
|
||||
k_d: parts[7],
|
||||
k_s: parts[8],
|
||||
exponent: parts[9],
|
||||
};
|
||||
|
||||
let idx = scene.materials.len();
|
||||
material_color = Some(idx);
|
||||
scene.materials.push(material);
|
||||
}
|
||||
|
||||
"sphere" => scene.objects.push(Object {
|
||||
kind: Box::new(Sphere {
|
||||
center: read_vec3(0)?,
|
||||
radius: parts[3],
|
||||
}),
|
||||
material: match material_color {
|
||||
Some(v) => v,
|
||||
None => bail!("Each sphere must be preceded by a `mtlcolor` line"),
|
||||
},
|
||||
}),
|
||||
|
||||
"cylinder" => scene.objects.push(Object {
|
||||
kind: Box::new(Cylinder {
|
||||
center: read_vec3(0)?,
|
||||
direction: read_vec3(3)?,
|
||||
radius: parts[6],
|
||||
length: parts[7],
|
||||
}),
|
||||
material: match material_color {
|
||||
Some(v) => v,
|
||||
None => bail!("Each sphere must be preceded by a `mtlcolor` line"),
|
||||
},
|
||||
}),
|
||||
|
||||
_ => bail!("Unknown keyword {keyword}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(scene)
|
||||
}
|
|
@ -4,7 +4,6 @@ extern crate anyhow;
|
|||
extern crate derivative;
|
||||
|
||||
mod image;
|
||||
mod input_file;
|
||||
mod ray;
|
||||
mod scene;
|
||||
mod utils;
|
||||
|
@ -16,9 +15,9 @@ use anyhow::Result;
|
|||
use clap::Parser;
|
||||
use rayon::prelude::{IntoParallelIterator, ParallelIterator};
|
||||
use scene::data::ObjectKind;
|
||||
use scene::Scene;
|
||||
|
||||
use crate::image::Image;
|
||||
use crate::input_file::parse_input_file;
|
||||
use crate::ray::Ray;
|
||||
|
||||
/// Simple raycaster.
|
||||
|
@ -49,7 +48,7 @@ fn main() -> Result<()> {
|
|||
.output_path
|
||||
.unwrap_or_else(|| opt.input_path.with_extension("ppm"));
|
||||
|
||||
let mut scene = parse_input_file(&opt.input_path)?;
|
||||
let mut scene = Scene::from_input_file(&opt.input_path)?;
|
||||
let distance = opt.distance;
|
||||
|
||||
if opt.force_parallel {
|
||||
|
|
|
@ -7,6 +7,8 @@ use ordered_float::NotNan;
|
|||
use crate::image::Color;
|
||||
use crate::ray::Ray;
|
||||
|
||||
use super::Scene;
|
||||
|
||||
pub trait ObjectKind: Debug + Send + Sync {
|
||||
/// Determine where the ray intersects this object, returning the earliest
|
||||
/// time this happens. Returns None if no intersection occurs.
|
||||
|
@ -64,24 +66,12 @@ pub struct Light {
|
|||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Scene {
|
||||
pub eye_pos: Vector3<f64>,
|
||||
pub view_dir: Vector3<f64>,
|
||||
pub up_dir: Vector3<f64>,
|
||||
|
||||
/// Horizontal field of view (in degrees)
|
||||
pub hfov: f64,
|
||||
pub parallel_projection: bool,
|
||||
|
||||
pub image_width: usize,
|
||||
pub image_height: usize,
|
||||
|
||||
/// Background color
|
||||
pub bkg_color: Color,
|
||||
|
||||
pub materials: Vec<Material>,
|
||||
pub lights: Vec<Light>,
|
||||
pub objects: Vec<Object>,
|
||||
pub struct DepthCueing {
|
||||
color: Color,
|
||||
a_max: f64,
|
||||
a_min: f64,
|
||||
dist_max: f64,
|
||||
dist_min: f64,
|
||||
}
|
||||
|
||||
/// Information about an intersection
|
||||
|
@ -130,6 +120,7 @@ impl Scene {
|
|||
|
||||
let ambient_component = material.k_a * material.diffuse_color;
|
||||
|
||||
// Diffuse and specular lighting for each separate light
|
||||
let diffuse_and_specular: Vector3<f64> = self
|
||||
.lights
|
||||
.iter()
|
||||
|
|
142
assignment-1b/src/scene/input_file.rs
Normal file
142
assignment-1b/src/scene/input_file.rs
Normal file
|
@ -0,0 +1,142 @@
|
|||
use std::{fs::File, io::Read, path::Path};
|
||||
|
||||
use anyhow::Result;
|
||||
use nalgebra::Vector3;
|
||||
|
||||
use crate::scene::{
|
||||
cylinder::Cylinder,
|
||||
data::{Light, LightKind, Material, Object},
|
||||
sphere::Sphere,
|
||||
Scene,
|
||||
};
|
||||
|
||||
impl Scene {
|
||||
/// Parse the input file into a scene
|
||||
pub fn from_input_file(path: impl AsRef<Path>) -> Result<Self> {
|
||||
let contents = {
|
||||
let mut contents = String::new();
|
||||
let mut file = File::open(path.as_ref())?;
|
||||
file.read_to_string(&mut contents)?;
|
||||
contents
|
||||
};
|
||||
|
||||
let mut scene = Scene::default();
|
||||
let mut material_color = None;
|
||||
|
||||
for line in contents.lines() {
|
||||
let mut parts = line.split_whitespace();
|
||||
let keyword = match parts.next() {
|
||||
Some(v) => v,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
if keyword == "imsize" {
|
||||
let parts = parts
|
||||
.map(|s| s.parse::<usize>().map_err(|e| e.into()))
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
if let [width, height] = parts[..] {
|
||||
scene.image_width = width;
|
||||
scene.image_height = height;
|
||||
}
|
||||
} else if keyword == "projection" {
|
||||
if let Some("parallel") = parts.next() {
|
||||
scene.parallel_projection = true;
|
||||
}
|
||||
}
|
||||
// Do float parsing instead
|
||||
else {
|
||||
let parts = parts
|
||||
.map(|s| s.parse::<f64>().map_err(|e| e.into()))
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
let read_vec3 = |start: usize| {
|
||||
if parts.len() < start + 3 {
|
||||
bail!("Vec3 requires 3 components.");
|
||||
}
|
||||
Ok(Vector3::new(
|
||||
parts[start],
|
||||
parts[start + 1],
|
||||
parts[start + 2],
|
||||
))
|
||||
};
|
||||
|
||||
match keyword {
|
||||
"eye" => scene.eye_pos = read_vec3(0)?,
|
||||
"viewdir" => scene.view_dir = read_vec3(0)?,
|
||||
"updir" => scene.up_dir = read_vec3(0)?,
|
||||
|
||||
"hfov" => scene.hfov = parts[0],
|
||||
"bkgcolor" => scene.bkg_color = read_vec3(0)?,
|
||||
|
||||
"light" => {
|
||||
let kind = match parts[3] as usize {
|
||||
0 => LightKind::Directional {
|
||||
direction: read_vec3(0)?,
|
||||
},
|
||||
1 => LightKind::Point {
|
||||
location: read_vec3(0)?,
|
||||
},
|
||||
_ => bail!("Invalid w"),
|
||||
};
|
||||
let light = Light {
|
||||
kind,
|
||||
color: read_vec3(4)?,
|
||||
};
|
||||
scene.lights.push(light);
|
||||
}
|
||||
|
||||
// mtlcolor Odr Odg Odb Osr Osg Osb ka kd ks n
|
||||
"mtlcolor" => {
|
||||
let diffuse_color = read_vec3(0)?;
|
||||
let specular_color = read_vec3(3)?;
|
||||
|
||||
let material = Material {
|
||||
diffuse_color,
|
||||
specular_color,
|
||||
k_a: parts[6],
|
||||
k_d: parts[7],
|
||||
k_s: parts[8],
|
||||
exponent: parts[9],
|
||||
};
|
||||
|
||||
let idx = scene.materials.len();
|
||||
material_color = Some(idx);
|
||||
scene.materials.push(material);
|
||||
}
|
||||
|
||||
"sphere" => scene.objects.push(Object {
|
||||
kind: Box::new(Sphere {
|
||||
center: read_vec3(0)?,
|
||||
radius: parts[3],
|
||||
}),
|
||||
material: match material_color {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
bail!("Each sphere must be preceded by a `mtlcolor` line")
|
||||
}
|
||||
},
|
||||
}),
|
||||
|
||||
"cylinder" => scene.objects.push(Object {
|
||||
kind: Box::new(Cylinder {
|
||||
center: read_vec3(0)?,
|
||||
direction: read_vec3(3)?,
|
||||
radius: parts[6],
|
||||
length: parts[7],
|
||||
}),
|
||||
material: match material_color {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
bail!("Each sphere must be preceded by a `mtlcolor` line")
|
||||
}
|
||||
},
|
||||
}),
|
||||
|
||||
_ => bail!("Unknown keyword {keyword}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(scene)
|
||||
}
|
||||
}
|
|
@ -1,3 +1,32 @@
|
|||
pub mod data;
|
||||
pub mod sphere;
|
||||
pub mod cylinder;
|
||||
pub mod data;
|
||||
pub mod input_file;
|
||||
pub mod sphere;
|
||||
|
||||
use nalgebra::Vector3;
|
||||
|
||||
use crate::image::Color;
|
||||
|
||||
use self::data::{DepthCueing, Light, Material, Object};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Scene {
|
||||
pub eye_pos: Vector3<f64>,
|
||||
pub view_dir: Vector3<f64>,
|
||||
pub up_dir: Vector3<f64>,
|
||||
|
||||
/// Horizontal field of view (in degrees)
|
||||
pub hfov: f64,
|
||||
pub parallel_projection: bool,
|
||||
|
||||
pub image_width: usize,
|
||||
pub image_height: usize,
|
||||
|
||||
/// Background color
|
||||
pub bkg_color: Color,
|
||||
pub depth_cueing: DepthCueing,
|
||||
|
||||
pub materials: Vec<Material>,
|
||||
pub lights: Vec<Light>,
|
||||
pub objects: Vec<Object>,
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue