Added AssemblyBuilder and got instancing working (sans testing...).
The AssemblyBuilder is responsible for collecting the data needed to actually create an Assembly. AssemblyBuilders are now the only way to create an Assembly, which guarantees that Assemblies aren't half-baked. Also got instancing working with transforms and such. It may not be _really_ working because I don't have a complex test case for it yet. But that will come later.
This commit is contained in:
parent
901fc88f63
commit
4988a6d1e6
|
@ -16,31 +16,49 @@ pub struct Assembly {
|
|||
|
||||
// Object list
|
||||
pub objects: Vec<Object>,
|
||||
object_map: HashMap<String, usize>, // map Name -> Index
|
||||
|
||||
// Assembly list
|
||||
pub assemblies: Vec<Assembly>,
|
||||
assembly_map: HashMap<String, usize>, // map Name -> Index
|
||||
|
||||
// Object accel
|
||||
pub object_accel: BVH,
|
||||
}
|
||||
|
||||
impl Assembly {
|
||||
pub fn new() -> Assembly {
|
||||
Assembly {
|
||||
impl Boundable for Assembly {
|
||||
fn bounds<'a>(&'a self) -> &'a [BBox] {
|
||||
self.object_accel.bounds()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AssemblyBuilder {
|
||||
// Instance list
|
||||
instances: Vec<Instance>,
|
||||
xforms: Vec<Matrix4x4>,
|
||||
|
||||
// Object list
|
||||
objects: Vec<Object>,
|
||||
object_map: HashMap<String, usize>, // map Name -> Index
|
||||
|
||||
// Assembly list
|
||||
assemblies: Vec<Assembly>,
|
||||
assembly_map: HashMap<String, usize>, // map Name -> Index
|
||||
}
|
||||
|
||||
|
||||
impl AssemblyBuilder {
|
||||
pub fn new() -> AssemblyBuilder {
|
||||
AssemblyBuilder {
|
||||
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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub fn add_object(&mut self, name: &str, obj: Object) {
|
||||
self.object_map.insert(name.to_string(), self.objects.len());
|
||||
self.objects.push(obj);
|
||||
|
@ -81,31 +99,29 @@ impl Assembly {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn finalize(&mut self) {
|
||||
// Clear maps (no longer needed).
|
||||
// However, don't clear shader maps, as they are still used by
|
||||
// get_surface_shader() et al.
|
||||
self.object_map.clear();
|
||||
self.assembly_map.clear();
|
||||
|
||||
pub fn build(mut self) -> Assembly {
|
||||
// Shrink storage to minimum.
|
||||
// However, don't shrink shader storage, because there are pointers to
|
||||
// that data that could get invalidated.
|
||||
self.instances.shrink_to_fit();
|
||||
self.xforms.shrink_to_fit();
|
||||
self.objects.shrink_to_fit();
|
||||
self.object_map.shrink_to_fit();
|
||||
self.assemblies.shrink_to_fit();
|
||||
self.assembly_map.shrink_to_fit();
|
||||
|
||||
// Build object accel
|
||||
let (bis, bbs) = self.instance_bounds();
|
||||
println!("Len: {}, {}", bis.len(), bbs.len());
|
||||
self.object_accel = BVH::from_objects(&mut self.instances[..],
|
||||
1,
|
||||
|inst| &bbs[bis[inst.id]..bis[inst.id + 1]]);
|
||||
}
|
||||
let object_accel = BVH::from_objects(&mut self.instances[..],
|
||||
1,
|
||||
|inst| &bbs[bis[inst.id]..bis[inst.id + 1]]);
|
||||
|
||||
Assembly {
|
||||
instances: self.instances,
|
||||
xforms: self.xforms,
|
||||
objects: self.objects,
|
||||
assemblies: self.assemblies,
|
||||
object_accel: object_accel,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Returns a pair of vectors with the bounds of all instances.
|
||||
|
@ -121,16 +137,17 @@ impl Assembly {
|
|||
// Get bounding boxes
|
||||
match inst.instance_type {
|
||||
InstanceType::Object => {
|
||||
// Push bounds onto bbs
|
||||
let obj = &self.objects[inst.data_index];
|
||||
// TODO: push bounds onto bbs
|
||||
match obj {
|
||||
&Object::Surface(ref s) => bbs.extend(s.bounds()),
|
||||
}
|
||||
}
|
||||
|
||||
InstanceType::Assembly => {
|
||||
// Push bounds onto bbs
|
||||
let asmb = &self.assemblies[inst.data_index];
|
||||
// TODO: push bounds onto bbs
|
||||
bbs.extend(asmb.bounds());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,6 +170,7 @@ impl Assembly {
|
|||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Object {
|
||||
Surface(Box<Surface>),
|
||||
|
|
12
src/main.rs
12
src/main.rs
|
@ -33,7 +33,7 @@ use math::{Point, Matrix4x4};
|
|||
use ray::Ray;
|
||||
use camera::Camera;
|
||||
use scene::Scene;
|
||||
use assembly::{Assembly, Object};
|
||||
use assembly::{AssemblyBuilder, Object};
|
||||
use renderer::Renderer;
|
||||
use surface::triangle_mesh::TriangleMesh;
|
||||
use parse::DataTree;
|
||||
|
@ -132,11 +132,11 @@ fn main() {
|
|||
vec![20.0],
|
||||
vec![1026.0]);
|
||||
|
||||
let mut assembly = Assembly::new();
|
||||
assembly.add_object("yar", Object::Surface(Box::new(mesh)));
|
||||
assembly.add_object_instance("yar",
|
||||
Some(&[Matrix4x4::from_location(Point::new(0.0, 0.0, 0.0))]));
|
||||
assembly.finalize();
|
||||
let mut assembly_b = AssemblyBuilder::new();
|
||||
assembly_b.add_object("yar", Object::Surface(Box::new(mesh)));
|
||||
assembly_b.add_object_instance("yar",
|
||||
Some(&[Matrix4x4::from_location(Point::new(25.0, 0.0, 0.0))]));
|
||||
let assembly = assembly_b.build();
|
||||
|
||||
let scene = Scene {
|
||||
name: None,
|
||||
|
|
|
@ -4,7 +4,7 @@ use std;
|
|||
use std::ops::{Index, IndexMut, Mul};
|
||||
|
||||
use float4::Float4;
|
||||
use lerp::Lerp;
|
||||
use lerp::{Lerp, lerp_slice};
|
||||
|
||||
use super::Point;
|
||||
|
||||
|
@ -248,6 +248,32 @@ impl Lerp for Matrix4x4 {
|
|||
}
|
||||
|
||||
|
||||
pub fn multiply_matrix_slices(xforms1: &[Matrix4x4],
|
||||
xforms2: &[Matrix4x4],
|
||||
xforms_out: &mut Vec<Matrix4x4>) {
|
||||
xforms_out.clear();
|
||||
|
||||
// Transform the bounding boxes
|
||||
if xforms1.len() == 0 || xforms2.len() == 0 {
|
||||
return;
|
||||
} else if xforms1.len() == xforms2.len() {
|
||||
for (xf1, xf2) in Iterator::zip(xforms1.iter(), xforms2.iter()) {
|
||||
xforms_out.push(*xf1 * *xf2);
|
||||
}
|
||||
} else if xforms1.len() > xforms2.len() {
|
||||
let s = (xforms1.len() - 1) as f32;
|
||||
for (i, xf) in xforms1.iter().enumerate() {
|
||||
xforms_out.push(*xf * lerp_slice(xforms2, i as f32 / s));
|
||||
}
|
||||
} else if xforms1.len() < xforms2.len() {
|
||||
let s = (xforms2.len() - 1) as f32;
|
||||
for (i, xf) in xforms2.iter().enumerate() {
|
||||
xforms_out.push(lerp_slice(xforms1, i as f32 / s) * *xf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
|
@ -8,7 +8,7 @@ mod matrix;
|
|||
pub use self::vector::Vector;
|
||||
pub use self::normal::Normal;
|
||||
pub use self::point::Point;
|
||||
pub use self::matrix::Matrix4x4;
|
||||
pub use self::matrix::{Matrix4x4, multiply_matrix_slices};
|
||||
|
||||
/// Trait for calculating dot products.
|
||||
pub trait DotProduct
|
||||
|
|
|
@ -2,7 +2,8 @@ use std::iter;
|
|||
use std::slice;
|
||||
use std::cell::UnsafeCell;
|
||||
|
||||
use math::Matrix4x4;
|
||||
use math::{Matrix4x4, multiply_matrix_slices};
|
||||
use lerp::lerp_slice;
|
||||
use assembly::{Assembly, Object, Instance, InstanceType};
|
||||
use ray::Ray;
|
||||
use surface::SurfaceIntersection;
|
||||
|
@ -11,6 +12,7 @@ pub struct Tracer<'a> {
|
|||
root: &'a Assembly,
|
||||
rays: UnsafeCell<Vec<Ray>>, // Should only be used from trace(), not any other methods
|
||||
xform_stack: Vec<Matrix4x4>,
|
||||
xform_stack_indices: Vec<usize>,
|
||||
isects: Vec<SurfaceIntersection>,
|
||||
}
|
||||
|
||||
|
@ -18,8 +20,9 @@ impl<'a> Tracer<'a> {
|
|||
pub fn from_assembly(assembly: &'a Assembly) -> Tracer<'a> {
|
||||
Tracer {
|
||||
root: assembly,
|
||||
xform_stack: Vec::new(),
|
||||
rays: UnsafeCell::new(Vec::new()),
|
||||
xform_stack: Vec::new(),
|
||||
xform_stack_indices: vec![0],
|
||||
isects: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +60,35 @@ impl<'a> Tracer<'a> {
|
|||
|
||||
fn trace_assembly<'b>(&'b mut self, assembly: &Assembly, wrays: &[Ray], rays: &mut [Ray]) {
|
||||
assembly.object_accel.traverse(&mut rays[..], &assembly.instances[..], |inst, rs| {
|
||||
// TODO: transform rays
|
||||
// Transform rays if needed
|
||||
if let Some((xstart, xend)) = inst.transform_indices {
|
||||
// Push transforms to stack
|
||||
let mut combined = Vec::new();
|
||||
if self.xform_stack.len() == 0 {
|
||||
self.xform_stack.extend(&assembly.xforms[xstart..xend]);
|
||||
} else {
|
||||
let x2start = self.xform_stack_indices[self.xform_stack_indices.len() - 2];
|
||||
let x2end = self.xform_stack_indices[self.xform_stack_indices.len() - 1];
|
||||
multiply_matrix_slices(&self.xform_stack[x2start..x2end],
|
||||
&assembly.xforms[xstart..xend],
|
||||
&mut combined);
|
||||
self.xform_stack.extend(&combined);
|
||||
}
|
||||
self.xform_stack_indices.push(self.xform_stack.len());
|
||||
|
||||
// Do transforms
|
||||
let xstart = self.xform_stack_indices[self.xform_stack_indices.len() - 2];
|
||||
let xend = self.xform_stack_indices[self.xform_stack_indices.len() - 1];
|
||||
let xforms = &self.xform_stack[xstart..xend];
|
||||
for ray in &mut rs[..] {
|
||||
let id = ray.id;
|
||||
let t = ray.time;
|
||||
*ray = wrays[id as usize];
|
||||
ray.transform(&lerp_slice(xforms, t));
|
||||
}
|
||||
}
|
||||
|
||||
// Trace rays
|
||||
match inst.instance_type {
|
||||
InstanceType::Object => {
|
||||
self.trace_object(&assembly.objects[inst.data_index], wrays, rs);
|
||||
|
@ -67,6 +98,35 @@ impl<'a> Tracer<'a> {
|
|||
self.trace_assembly(&assembly.assemblies[inst.data_index], wrays, rs);
|
||||
}
|
||||
}
|
||||
|
||||
// Un-transform rays if needed
|
||||
if let Some(_) = inst.transform_indices {
|
||||
// Pop transforms off stack
|
||||
let xstart = self.xform_stack_indices[self.xform_stack_indices.len() - 2];
|
||||
let xend = self.xform_stack_indices[self.xform_stack_indices.len() - 1];
|
||||
let l = self.xform_stack.len();
|
||||
self.xform_stack.resize(l - (xend - xstart), Matrix4x4::new());
|
||||
self.xform_stack_indices.pop();
|
||||
|
||||
// Undo transforms
|
||||
if self.xform_stack.len() > 0 {
|
||||
let xstart = self.xform_stack_indices[self.xform_stack_indices.len() - 2];
|
||||
let xend = self.xform_stack_indices[self.xform_stack_indices.len() - 1];
|
||||
let xforms = &self.xform_stack[xstart..xend];
|
||||
for ray in &mut rs[..] {
|
||||
let id = ray.id;
|
||||
let t = ray.time;
|
||||
*ray = wrays[id as usize];
|
||||
ray.transform(&lerp_slice(xforms, t));
|
||||
}
|
||||
} else {
|
||||
for ray in &mut rs[..] {
|
||||
let id = ray.id;
|
||||
let t = ray.time;
|
||||
*ray = wrays[id as usize];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user