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:
Nathan Vegdahl 2016-03-12 00:33:11 -08:00
parent 38d33ed144
commit e96798ab6b
10 changed files with 356 additions and 52 deletions

View File

@ -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 {

View File

@ -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();

View File

@ -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();

View File

@ -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() {

View File

@ -1,5 +1,6 @@
mod data_tree;
mod psy;
mod psy_assembly;
pub mod basics;
pub use self::data_tree::DataTree;

View File

@ -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
View 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!()
}

View File

@ -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;

View File

@ -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
View 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>,
}