Lazily committing a bunch of stuff.
Includes: - More scene parsing code. Making good progress! - Making the rendering code actually use the Scene and Assembly types. - Bare beginnings of a Tracer type.
This commit is contained in:
parent
38d33ed144
commit
e96798ab6b
|
@ -2,7 +2,8 @@ use std::collections::HashMap;
|
|||
|
||||
use math::Matrix4x4;
|
||||
use bvh::BVH;
|
||||
use surface::Surface;
|
||||
use surface::{Surface, SurfaceIntersection};
|
||||
use ray::Ray;
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -23,6 +24,38 @@ pub struct Assembly {
|
|||
object_accel: BVH,
|
||||
}
|
||||
|
||||
impl Assembly {
|
||||
pub fn new() -> Assembly {
|
||||
Assembly {
|
||||
instances: Vec::new(),
|
||||
xforms: Vec::new(),
|
||||
objects: Vec::new(),
|
||||
object_map: HashMap::new(),
|
||||
assemblies: Vec::new(),
|
||||
assembly_map: HashMap::new(),
|
||||
object_accel: BVH::new_empty(),
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this is just temporary. Remove this and move tracing functionality
|
||||
// into the tracer.
|
||||
pub fn intersect_rays(&self, rays: &mut [Ray], isects: &mut [SurfaceIntersection]) {
|
||||
for obj in self.objects.iter() {
|
||||
match obj {
|
||||
&Object::Surface(ref surface) => {
|
||||
surface.intersect_rays(rays, isects);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn add_object(&mut self, name: &str, obj: Object) {
|
||||
self.object_map.insert(name.to_string(), self.objects.len());
|
||||
self.objects.push(obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Object {
|
||||
|
|
14
src/bvh.rs
14
src/bvh.rs
|
@ -28,15 +28,19 @@ enum BVHNode {
|
|||
}
|
||||
|
||||
impl BVH {
|
||||
pub fn from_objects<'a, T, F>(objects: &mut [T], objects_per_leaf: usize, bounder: F) -> BVH
|
||||
where F: 'a + Fn(&T) -> &'a [BBox]
|
||||
{
|
||||
let mut bvh = BVH {
|
||||
pub fn new_empty() -> BVH {
|
||||
BVH {
|
||||
nodes: Vec::new(),
|
||||
bounds: Vec::new(),
|
||||
depth: 0,
|
||||
bounds_cache: Vec::new(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_objects<'a, T, F>(objects: &mut [T], objects_per_leaf: usize, bounder: F) -> BVH
|
||||
where F: 'a + Fn(&T) -> &'a [BBox]
|
||||
{
|
||||
let mut bvh = BVH::new_empty();
|
||||
|
||||
bvh.recursive_build(0, 0, objects_per_leaf, objects, &bounder);
|
||||
bvh.bounds_cache.clear();
|
||||
|
|
16
src/main.rs
16
src/main.rs
|
@ -12,6 +12,7 @@ mod bbox;
|
|||
mod camera;
|
||||
mod parse;
|
||||
mod renderer;
|
||||
mod tracer;
|
||||
mod image;
|
||||
mod triangle;
|
||||
mod surface;
|
||||
|
@ -30,6 +31,8 @@ use docopt::Docopt;
|
|||
use math::{Point, Matrix4x4};
|
||||
use ray::Ray;
|
||||
use camera::Camera;
|
||||
use scene::Scene;
|
||||
use assembly::{Assembly, Object};
|
||||
use renderer::Renderer;
|
||||
use surface::triangle_mesh::TriangleMesh;
|
||||
use parse::DataTree;
|
||||
|
@ -128,12 +131,21 @@ fn main() {
|
|||
vec![20.0],
|
||||
vec![1026.0]);
|
||||
|
||||
let mut assembly = Assembly::new();
|
||||
assembly.add_object("yar", Object::Surface(Box::new(mesh)));
|
||||
|
||||
let scene = Scene {
|
||||
name: None,
|
||||
background_color: (0.0, 0.0, 0.0),
|
||||
camera: cam,
|
||||
root: assembly,
|
||||
};
|
||||
|
||||
let r = Renderer {
|
||||
output_file: args.arg_imgpath.clone(),
|
||||
resolution: (512, 512),
|
||||
spp: samples_per_pixel as usize,
|
||||
camera: cam,
|
||||
scene: mesh,
|
||||
scene: scene,
|
||||
};
|
||||
|
||||
r.render();
|
||||
|
|
|
@ -42,6 +42,34 @@ impl<'a> DataTree<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn type_name(&'a self) -> &'a str {
|
||||
match self {
|
||||
&DataTree::Internal{type_name, ..} => type_name,
|
||||
&DataTree::Leaf{type_name, ..} => type_name,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_internal(&self) -> bool {
|
||||
match self {
|
||||
&DataTree::Internal{..} => true,
|
||||
&DataTree::Leaf{..} => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_leaf(&self) -> bool {
|
||||
match self {
|
||||
&DataTree::Internal{..} => false,
|
||||
&DataTree::Leaf{..} => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn leaf_contents(&'a self) -> Option<&'a str> {
|
||||
match self {
|
||||
&DataTree::Internal{..} => None,
|
||||
&DataTree::Leaf{contents, ..} => Some(contents),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_first_child_with_type_name(&'a self, type_name: &str) -> Option<&'a DataTree> {
|
||||
if let &DataTree::Internal { ref children, .. } = self {
|
||||
for child in children.iter() {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
mod data_tree;
|
||||
mod psy;
|
||||
mod psy_assembly;
|
||||
pub mod basics;
|
||||
|
||||
pub use self::data_tree::DataTree;
|
||||
|
|
262
src/parse/psy.rs
262
src/parse/psy.rs
|
@ -5,9 +5,16 @@ use std::result::Result;
|
|||
use nom;
|
||||
use nom::IResult;
|
||||
|
||||
use renderer::Renderer;
|
||||
use super::DataTree;
|
||||
use super::basics::ws_u32;
|
||||
use super::basics::{ws_u32, ws_f32};
|
||||
use super::psy_assembly::parse_assembly;
|
||||
|
||||
use math::Matrix4x4;
|
||||
use camera::Camera;
|
||||
use renderer::Renderer;
|
||||
use scene::Scene;
|
||||
|
||||
|
||||
|
||||
|
||||
/// Takes in a DataTree representing a Scene node and returns
|
||||
|
@ -31,8 +38,59 @@ pub fn parse_frame(tree: &DataTree) -> Result<Renderer, ()> {
|
|||
}
|
||||
|
||||
// Parse output info
|
||||
let output_info = if let &DataTree::Internal{ref children, ..} =
|
||||
tree.get_first_child_with_type_name("Output").unwrap() {
|
||||
let output_info = try!(parse_output_info(tree.get_first_child_with_type_name("Output")
|
||||
.unwrap()));
|
||||
|
||||
// Parse render settings
|
||||
let render_settings = try!(parse_render_settings(tree.get_first_child_with_type_name("Rende\
|
||||
rSett\
|
||||
ings")
|
||||
.unwrap()));
|
||||
|
||||
// Parse camera
|
||||
let camera = try!(parse_camera(tree.get_first_child_with_type_name("Camera").unwrap()));
|
||||
|
||||
// Parse world
|
||||
let world = try!(parse_world(tree.get_first_child_with_type_name("World").unwrap()));
|
||||
|
||||
// Parse root scene assembly
|
||||
let assembly = try!(parse_assembly(tree.get_first_child_with_type_name("Assembly").unwrap()));
|
||||
|
||||
// Put scene together
|
||||
let scene_name = if let &DataTree::Internal{ident, ..} = tree {
|
||||
if let Some(name) = ident {
|
||||
Some(name.to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let scene = Scene {
|
||||
name: scene_name,
|
||||
background_color: world,
|
||||
camera: camera,
|
||||
root: assembly,
|
||||
};
|
||||
|
||||
// // Put renderer together
|
||||
// let renderer = Renderer {
|
||||
// output_file: output_info.0.clone(),
|
||||
// resolution: (render_settings.0.0 as usize, render_settings.0.1 as usize),
|
||||
// spp: render_settings.1,
|
||||
// scene: scene,
|
||||
// }
|
||||
//
|
||||
// return Ok(renderer);
|
||||
|
||||
return Err(());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
fn parse_output_info(tree: &DataTree) -> Result<(String), ()> {
|
||||
if let &DataTree::Internal{ref children, ..} = tree {
|
||||
let mut found_path = false;
|
||||
let mut path = String::new();
|
||||
|
||||
|
@ -44,37 +102,25 @@ pub fn parse_frame(tree: &DataTree) -> Result<Renderer, ()> {
|
|||
path = contents.to_string();
|
||||
}
|
||||
|
||||
&DataTree::Leaf { type_name, contents } if type_name == "FileFormat" => {
|
||||
// TODO
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
&DataTree::Leaf { type_name, contents } if type_name == "ColorSpace" => {
|
||||
// TODO
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
&DataTree::Leaf { type_name, contents } if type_name == "Dither" => {
|
||||
// TODO
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if found_path {
|
||||
(path)
|
||||
return Ok((path));
|
||||
} else {
|
||||
return Err(());
|
||||
}
|
||||
} else {
|
||||
return Err(());
|
||||
};
|
||||
}
|
||||
|
||||
// Parse render settings
|
||||
let render_settings = if let &DataTree::Internal{ref children, ..} =
|
||||
tree.get_first_child_with_type_name("RenderSettings").unwrap() {
|
||||
|
||||
|
||||
|
||||
fn parse_render_settings(tree: &DataTree) -> Result<((u32, u32), u32, u32), ()> {
|
||||
if let &DataTree::Internal{ref children, ..} = tree {
|
||||
let mut found_res = false;
|
||||
let mut found_spp = false;
|
||||
let mut res = (0, 0);
|
||||
|
@ -95,6 +141,7 @@ pub fn parse_frame(tree: &DataTree) -> Result<Renderer, ()> {
|
|||
}
|
||||
}
|
||||
|
||||
// SamplesPerPixel
|
||||
&DataTree::Leaf { type_name, contents } if type_name == "SamplesPerPixel" => {
|
||||
if let IResult::Done(_, n) = ws_u32(contents.as_bytes()) {
|
||||
found_spp = true;
|
||||
|
@ -105,6 +152,7 @@ pub fn parse_frame(tree: &DataTree) -> Result<Renderer, ()> {
|
|||
}
|
||||
}
|
||||
|
||||
// Seed
|
||||
&DataTree::Leaf { type_name, contents } if type_name == "Seed" => {
|
||||
if let IResult::Done(_, n) = ws_u32(contents.as_bytes()) {
|
||||
seed = n;
|
||||
|
@ -119,19 +167,169 @@ pub fn parse_frame(tree: &DataTree) -> Result<Renderer, ()> {
|
|||
}
|
||||
|
||||
if found_res && found_spp {
|
||||
(res, spp)
|
||||
return Ok((res, spp, seed));
|
||||
} else {
|
||||
return Err(());
|
||||
}
|
||||
} else {
|
||||
return Err(());
|
||||
};
|
||||
|
||||
// Parse camera
|
||||
|
||||
// Parse world
|
||||
|
||||
// Parse root scene assembly
|
||||
|
||||
return Err(());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
fn parse_camera(tree: &DataTree) -> Result<Camera, ()> {
|
||||
if let &DataTree::Internal{ref children, ..} = tree {
|
||||
let mut mats = Vec::new();
|
||||
let mut fovs = Vec::new();
|
||||
let mut focus_distances = Vec::new();
|
||||
let mut aperture_radii = Vec::new();
|
||||
|
||||
// Parse
|
||||
for child in children.iter() {
|
||||
match child {
|
||||
// Fov
|
||||
&DataTree::Leaf { type_name, contents } if type_name == "Fov" => {
|
||||
if let IResult::Done(_, fov) = ws_f32(contents.as_bytes()) {
|
||||
fovs.push(fov * (3.1415926536 / 180.0));
|
||||
} else {
|
||||
// Found Fov, but its contents is not in the right format
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
|
||||
// FocalDistance
|
||||
&DataTree::Leaf { type_name, contents } if type_name == "FocalDistance" => {
|
||||
if let IResult::Done(_, fd) = ws_f32(contents.as_bytes()) {
|
||||
focus_distances.push(fd);
|
||||
} else {
|
||||
// Found FocalDistance, but its contents is not in the right format
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
|
||||
// ApertureRadius
|
||||
&DataTree::Leaf { type_name, contents } if type_name == "ApertureRadius" => {
|
||||
if let IResult::Done(_, ar) = ws_f32(contents.as_bytes()) {
|
||||
aperture_radii.push(ar);
|
||||
} else {
|
||||
// Found ApertureRadius, but its contents is not in the right format
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
|
||||
// Transform
|
||||
&DataTree::Leaf { type_name, contents } if type_name == "Transform" => {
|
||||
if let Ok(mat) = parse_matrix(contents) {
|
||||
mats.push(mat);
|
||||
} else {
|
||||
// Found Transform, but its contents is not in the right format
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(Camera::new(mats, fovs, aperture_radii, focus_distances));
|
||||
} else {
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
fn parse_world(tree: &DataTree) -> Result<(f32, f32, f32), ()> {
|
||||
if tree.is_internal() {
|
||||
let mut found_background_color = false;
|
||||
let mut background_color = (0.0, 0.0, 0.0);
|
||||
|
||||
// Parse background shader
|
||||
let bgs = {
|
||||
if tree.count_children_with_type_name("BackgroundShader") != 1 {
|
||||
return Err(());
|
||||
}
|
||||
tree.get_first_child_with_type_name("BackgroundShader").unwrap()
|
||||
};
|
||||
let bgs_type = {
|
||||
if bgs.count_children_with_type_name("Type") != 1 {
|
||||
return Err(());
|
||||
}
|
||||
if let &DataTree::Leaf{contents, ..} = tree.get_first_child_with_type_name("Type")
|
||||
.unwrap() {
|
||||
contents.trim()
|
||||
} else {
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
match bgs_type {
|
||||
"Color" => {
|
||||
if let Some(&DataTree::Leaf{contents, ..}) =
|
||||
bgs.get_first_child_with_type_name("Color") {
|
||||
if let IResult::Done(_, color) = closure!(tuple!(ws_f32,
|
||||
ws_f32,
|
||||
ws_f32))(contents.trim()
|
||||
.as_bytes()) {
|
||||
found_background_color = true;
|
||||
background_color = color;
|
||||
} else {
|
||||
return Err(());
|
||||
}
|
||||
} else {
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
|
||||
_ => return Err(()),
|
||||
}
|
||||
|
||||
return Ok(background_color);
|
||||
} else {
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
fn parse_matrix(contents: &str) -> Result<Matrix4x4, ()> {
|
||||
if let IResult::Done(_, ns) = closure!(terminated!(tuple!(ws_f32,
|
||||
ws_f32,
|
||||
ws_f32,
|
||||
ws_f32,
|
||||
ws_f32,
|
||||
ws_f32,
|
||||
ws_f32,
|
||||
ws_f32,
|
||||
ws_f32,
|
||||
ws_f32,
|
||||
ws_f32,
|
||||
ws_f32,
|
||||
ws_f32,
|
||||
ws_f32,
|
||||
ws_f32,
|
||||
ws_f32),
|
||||
nom::eof))(contents.as_bytes()) {
|
||||
return Ok(Matrix4x4::new_from_values(ns.0,
|
||||
ns.1,
|
||||
ns.2,
|
||||
ns.3,
|
||||
ns.4,
|
||||
ns.5,
|
||||
ns.6,
|
||||
ns.7,
|
||||
ns.8,
|
||||
ns.9,
|
||||
ns.10,
|
||||
ns.11,
|
||||
ns.12,
|
||||
ns.13,
|
||||
ns.14,
|
||||
ns.15));
|
||||
} else {
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
|
|
18
src/parse/psy_assembly.rs
Normal file
18
src/parse/psy_assembly.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use std::result::Result;
|
||||
|
||||
use nom;
|
||||
use nom::IResult;
|
||||
|
||||
use super::DataTree;
|
||||
use super::basics::{ws_u32, ws_f32};
|
||||
|
||||
use math::Matrix4x4;
|
||||
use camera::Camera;
|
||||
use renderer::Renderer;
|
||||
use assembly::Assembly;
|
||||
|
||||
pub fn parse_assembly(tree: &DataTree) -> Result<Assembly, ()> {
|
||||
unimplemented!()
|
||||
}
|
|
@ -10,12 +10,12 @@ use surface;
|
|||
use surface::Surface;
|
||||
use scene::Scene;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Renderer {
|
||||
pub output_file: String,
|
||||
pub resolution: (usize, usize),
|
||||
pub spp: usize,
|
||||
pub camera: Camera,
|
||||
pub scene: surface::triangle_mesh::TriangleMesh,
|
||||
pub scene: Scene,
|
||||
}
|
||||
|
||||
impl Renderer {
|
||||
|
@ -39,11 +39,11 @@ impl Renderer {
|
|||
let mut ray = {
|
||||
let filter_x = fast_logit(halton::sample(3, offset + si as u32), 1.5);
|
||||
let filter_y = fast_logit(halton::sample(4, offset + si as u32), 1.5);
|
||||
self.camera.generate_ray((x as f32 + filter_x) * cmpx - 0.5,
|
||||
(y as f32 + filter_y) * cmpy - 0.5,
|
||||
halton::sample(0, offset + si as u32),
|
||||
halton::sample(1, offset + si as u32),
|
||||
halton::sample(2, offset + si as u32))
|
||||
self.scene.camera.generate_ray((x as f32 + filter_x) * cmpx - 0.5,
|
||||
(y as f32 + filter_y) * cmpy - 0.5,
|
||||
halton::sample(0, offset + si as u32),
|
||||
halton::sample(1, offset + si as u32),
|
||||
halton::sample(2, offset + si as u32))
|
||||
};
|
||||
ray.id = si as u32;
|
||||
rays.push(ray);
|
||||
|
@ -51,7 +51,7 @@ impl Renderer {
|
|||
}
|
||||
|
||||
// Test rays against scene
|
||||
self.scene.intersect_rays(&mut rays, &mut isects);
|
||||
self.scene.root.intersect_rays(&mut rays, &mut isects);
|
||||
|
||||
// Calculate color based on ray hits
|
||||
let mut r = 0.0;
|
||||
|
|
|
@ -4,8 +4,8 @@ use assembly::Assembly;
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct Scene {
|
||||
name: String,
|
||||
background_color: (f32, f32, f32),
|
||||
camera: Camera,
|
||||
root: Assembly,
|
||||
pub name: Option<String>,
|
||||
pub background_color: (f32, f32, f32),
|
||||
pub camera: Camera,
|
||||
pub root: Assembly,
|
||||
}
|
||||
|
|
10
src/tracer.rs
Normal file
10
src/tracer.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
use math::Matrix4x4;
|
||||
use ray::Ray;
|
||||
use surface::SurfaceIntersection;
|
||||
|
||||
pub struct Tracer<'a> {
|
||||
xform_stack: Vec<Matrix4x4>,
|
||||
world_rays: &'a [Ray],
|
||||
intersections: &'a mut [SurfaceIntersection],
|
||||
rays: Vec<Ray>,
|
||||
}
|
Loading…
Reference in New Issue
Block a user