Assemblies now use BVH accel and actually utilize instances.
This commit is contained in:
parent
b58ba10f9b
commit
901fc88f63
129
src/assembly.rs
129
src/assembly.rs
|
@ -2,8 +2,10 @@ use std::collections::HashMap;
|
|||
|
||||
use math::Matrix4x4;
|
||||
use bvh::BVH;
|
||||
use boundable::Boundable;
|
||||
use surface::{Surface, SurfaceIntersection};
|
||||
use ray::Ray;
|
||||
use bbox::{BBox, transform_bbox_slice_from};
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -43,6 +45,111 @@ impl Assembly {
|
|||
self.object_map.insert(name.to_string(), self.objects.len());
|
||||
self.objects.push(obj);
|
||||
}
|
||||
|
||||
pub fn add_assembly(&mut self, name: &str, asmb: Assembly) {
|
||||
self.assembly_map.insert(name.to_string(), self.assemblies.len());
|
||||
self.assemblies.push(asmb);
|
||||
}
|
||||
|
||||
pub fn add_object_instance(&mut self, name: &str, xforms: Option<&[Matrix4x4]>) {
|
||||
let instance = Instance {
|
||||
instance_type: InstanceType::Object,
|
||||
data_index: self.object_map[name],
|
||||
id: self.instances.len(),
|
||||
transform_indices: xforms.map(|xf| (self.xforms.len(), self.xforms.len() + xf.len())),
|
||||
};
|
||||
|
||||
self.instances.push(instance);
|
||||
|
||||
if let Some(xf) = xforms {
|
||||
self.xforms.extend(xf);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_assembly_instance(&mut self, name: &str, xforms: Option<&[Matrix4x4]>) {
|
||||
let instance = Instance {
|
||||
instance_type: InstanceType::Assembly,
|
||||
data_index: self.object_map[name],
|
||||
id: self.instances.len(),
|
||||
transform_indices: xforms.map(|xf| (self.xforms.len(), self.xforms.len() + xf.len())),
|
||||
};
|
||||
|
||||
self.instances.push(instance);
|
||||
|
||||
if let Some(xf) = xforms {
|
||||
self.xforms.extend(xf);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
// 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]]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Returns a pair of vectors with the bounds of all instances.
|
||||
/// This is used for building the assembly's BVH.
|
||||
fn instance_bounds(&self) -> (Vec<usize>, Vec<BBox>) {
|
||||
let mut indices = vec![0];
|
||||
let mut bounds = Vec::new();
|
||||
|
||||
for inst in self.instances.iter() {
|
||||
let mut bbs = Vec::new();
|
||||
let mut bbs2 = Vec::new();
|
||||
|
||||
// Get bounding boxes
|
||||
match inst.instance_type {
|
||||
InstanceType::Object => {
|
||||
let obj = &self.objects[inst.data_index];
|
||||
// TODO: push bounds onto bbs
|
||||
match obj {
|
||||
&Object::Surface(ref s) => bbs.extend(s.bounds()),
|
||||
}
|
||||
}
|
||||
|
||||
InstanceType::Assembly => {
|
||||
let asmb = &self.assemblies[inst.data_index];
|
||||
// TODO: push bounds onto bbs
|
||||
}
|
||||
}
|
||||
|
||||
// Transform the bounding boxes, if necessary
|
||||
if let Some((xstart, xend)) = inst.transform_indices {
|
||||
let xf = &self.xforms[xstart..xend];
|
||||
transform_bbox_slice_from(&bbs, &xf, &mut bbs2);
|
||||
} else {
|
||||
bbs2.clear();
|
||||
bbs2.extend(bbs);
|
||||
}
|
||||
|
||||
// Push transformed bounds onto vec
|
||||
bounds.extend(bbs2);
|
||||
indices.push(bounds.len());
|
||||
}
|
||||
|
||||
return (indices, bounds);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -53,15 +160,15 @@ pub enum Object {
|
|||
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum Instance {
|
||||
Object {
|
||||
data_index: usize,
|
||||
transform_indices: (usize, usize),
|
||||
shader_index: usize,
|
||||
},
|
||||
|
||||
Assembly {
|
||||
data_index: usize,
|
||||
transform_indices: (usize, usize),
|
||||
},
|
||||
pub struct Instance {
|
||||
pub instance_type: InstanceType,
|
||||
pub data_index: usize,
|
||||
pub id: usize,
|
||||
pub transform_indices: Option<(usize, usize)>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum InstanceType {
|
||||
Object,
|
||||
Assembly,
|
||||
}
|
||||
|
|
52
src/bbox.rs
52
src/bbox.rs
|
@ -2,9 +2,10 @@
|
|||
|
||||
use std;
|
||||
use std::ops::BitOr;
|
||||
use std::iter::Iterator;
|
||||
|
||||
use math::Point;
|
||||
use lerp::{lerp, Lerp};
|
||||
use math::{Point, Matrix4x4};
|
||||
use lerp::{lerp, lerp_slice, Lerp};
|
||||
use ray::Ray;
|
||||
|
||||
const BBOX_MAXT_ADJUST: f32 = 1.00000024;
|
||||
|
@ -53,6 +54,29 @@ impl BBox {
|
|||
// Did we hit?
|
||||
return hitt0.max(0.0) <= hitt1.min(ray.max_t);
|
||||
}
|
||||
|
||||
// Creates a new BBox transformed into a different space.
|
||||
pub fn transformed(&self, xform: Matrix4x4) -> BBox {
|
||||
// BBox corners
|
||||
let vs = [Point::new(self.min[0], self.min[1], self.min[2]),
|
||||
Point::new(self.min[0], self.min[1], self.max[2]),
|
||||
Point::new(self.min[0], self.max[1], self.min[2]),
|
||||
Point::new(self.min[0], self.max[1], self.max[2]),
|
||||
Point::new(self.max[0], self.min[1], self.min[2]),
|
||||
Point::new(self.max[0], self.min[1], self.max[2]),
|
||||
Point::new(self.max[0], self.max[1], self.min[2]),
|
||||
Point::new(self.max[0], self.max[1], self.max[2])];
|
||||
|
||||
// Transform BBox corners and make new bbox
|
||||
let mut b = BBox::new();
|
||||
for v in vs.iter() {
|
||||
let v = *v * xform;
|
||||
b.min = v.min(b.min);
|
||||
b.max = v.max(b.max);
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -75,3 +99,27 @@ impl Lerp for BBox {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn transform_bbox_slice_from(bbs_in: &[BBox], xforms: &[Matrix4x4], bbs_out: &mut Vec<BBox>) {
|
||||
bbs_out.clear();
|
||||
|
||||
// Transform the bounding boxes
|
||||
if xforms.len() == 0 {
|
||||
return;
|
||||
} else if bbs_in.len() == xforms.len() {
|
||||
for (bb, xf) in Iterator::zip(bbs_in.iter(), xforms.iter()) {
|
||||
bbs_out.push(bb.transformed(xf.inverse()));
|
||||
}
|
||||
} else if bbs_in.len() > xforms.len() {
|
||||
let s = (bbs_in.len() - 1) as f32;
|
||||
for (i, bb) in bbs_in.iter().enumerate() {
|
||||
bbs_out.push(bb.transformed(lerp_slice(xforms, i as f32 / s).inverse()));
|
||||
}
|
||||
} else if bbs_in.len() < xforms.len() {
|
||||
let s = (xforms.len() - 1) as f32;
|
||||
for (i, xf) in xforms.iter().enumerate() {
|
||||
bbs_out.push(lerp_slice(bbs_in, i as f32 / s).transformed(xf.inverse()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
7
src/boundable.rs
Normal file
7
src/boundable.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use bbox::BBox;
|
||||
|
||||
pub trait Boundable {
|
||||
fn bounds<'a>(&'a self) -> &'a [BBox];
|
||||
}
|
12
src/bvh.rs
12
src/bvh.rs
|
@ -2,6 +2,7 @@
|
|||
|
||||
use lerp::lerp_slice;
|
||||
use bbox::BBox;
|
||||
use boundable::Boundable;
|
||||
use ray::Ray;
|
||||
use algorithm::partition;
|
||||
|
||||
|
@ -217,3 +218,14 @@ impl BVH {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Boundable for BVH {
|
||||
fn bounds<'a>(&'a self) -> &'a [BBox] {
|
||||
match self.nodes[0] {
|
||||
BVHNode::Internal{bounds_range, ..} => &self.bounds[bounds_range.0..bounds_range.1],
|
||||
|
||||
BVHNode::Leaf{bounds_range, ..} => &self.bounds[bounds_range.0..bounds_range.1],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,9 +66,8 @@ impl Camera {
|
|||
|
||||
// Ray origin
|
||||
let orig = {
|
||||
let (u, v) = square_to_circle(aperture_radius * ((u * 2.0) - 1.0),
|
||||
aperture_radius * ((v * 2.0) - 1.0));
|
||||
Point::new(u, v, 0.0)
|
||||
let (u, v) = square_to_circle((u * 2.0) - 1.0, (v * 2.0) - 1.0);
|
||||
Point::new(aperture_radius * u, aperture_radius * v, 0.0)
|
||||
};
|
||||
|
||||
// Ray direction
|
||||
|
|
|
@ -14,6 +14,7 @@ mod parse;
|
|||
mod renderer;
|
||||
mod tracer;
|
||||
mod image;
|
||||
mod boundable;
|
||||
mod triangle;
|
||||
mod surface;
|
||||
mod bvh;
|
||||
|
@ -133,6 +134,9 @@ fn main() {
|
|||
|
||||
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 scene = Scene {
|
||||
name: None,
|
||||
|
|
|
@ -6,6 +6,7 @@ pub mod triangle_mesh;
|
|||
|
||||
use ray::Ray;
|
||||
use math::{Point, Normal, Matrix4x4};
|
||||
use boundable::Boundable;
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -21,6 +22,6 @@ pub enum SurfaceIntersection {
|
|||
},
|
||||
}
|
||||
|
||||
pub trait Surface: Debug {
|
||||
pub trait Surface: Boundable + Debug {
|
||||
fn intersect_rays(&self, rays: &mut [Ray], isects: &mut [SurfaceIntersection]);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ use math::{Point, Normal, Matrix4x4};
|
|||
use ray::Ray;
|
||||
use triangle;
|
||||
use bbox::BBox;
|
||||
use boundable::Boundable;
|
||||
use bvh::BVH;
|
||||
|
||||
use super::{Surface, SurfaceIntersection};
|
||||
|
@ -50,6 +51,12 @@ impl TriangleMesh {
|
|||
}
|
||||
}
|
||||
|
||||
impl Boundable for TriangleMesh {
|
||||
fn bounds<'a>(&'a self) -> &'a [BBox] {
|
||||
self.accel.bounds()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Surface for TriangleMesh {
|
||||
fn intersect_rays(&self, rays: &mut [Ray], isects: &mut [SurfaceIntersection]) {
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::slice;
|
|||
use std::cell::UnsafeCell;
|
||||
|
||||
use math::Matrix4x4;
|
||||
use assembly::{Assembly, Object};
|
||||
use assembly::{Assembly, Object, Instance, InstanceType};
|
||||
use ray::Ray;
|
||||
use surface::SurfaceIntersection;
|
||||
|
||||
|
@ -56,11 +56,24 @@ impl<'a> Tracer<'a> {
|
|||
}
|
||||
|
||||
fn trace_assembly<'b>(&'b mut self, assembly: &Assembly, wrays: &[Ray], rays: &mut [Ray]) {
|
||||
for obj in assembly.objects.iter() {
|
||||
match obj {
|
||||
&Object::Surface(ref surface) => {
|
||||
surface.intersect_rays(rays, &mut self.isects);
|
||||
assembly.object_accel.traverse(&mut rays[..], &assembly.instances[..], |inst, rs| {
|
||||
// TODO: transform rays
|
||||
match inst.instance_type {
|
||||
InstanceType::Object => {
|
||||
self.trace_object(&assembly.objects[inst.data_index], wrays, rs);
|
||||
}
|
||||
|
||||
InstanceType::Assembly => {
|
||||
self.trace_assembly(&assembly.assemblies[inst.data_index], wrays, rs);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn trace_object<'b>(&'b mut self, obj: &Object, wrays: &[Ray], rays: &mut [Ray]) {
|
||||
match obj {
|
||||
&Object::Surface(ref surface) => {
|
||||
surface.intersect_rays(rays, &mut self.isects);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user