All final intersections are now done in world space.
BVH traversal still happens in local space, but final actual surface intersection calculations are done in world space by transforming the triangle into world space. This is to improve numerical consistency between intersections.
This commit is contained in:
parent
e2954ba5b0
commit
18245b725c
|
@ -6,7 +6,7 @@ use std::iter::Iterator;
|
||||||
|
|
||||||
use math::{Point, Matrix4x4};
|
use math::{Point, Matrix4x4};
|
||||||
use lerp::{lerp, lerp_slice, Lerp};
|
use lerp::{lerp, lerp_slice, Lerp};
|
||||||
use ray::Ray;
|
use ray::AccelRay;
|
||||||
|
|
||||||
const BBOX_MAXT_ADJUST: f32 = 1.00000024;
|
const BBOX_MAXT_ADJUST: f32 = 1.00000024;
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ impl BBox {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns whether the given ray intersects with the bbox.
|
// Returns whether the given ray intersects with the bbox.
|
||||||
pub fn intersect_ray(&self, ray: &Ray) -> bool {
|
pub fn intersect_accel_ray(&self, ray: &AccelRay) -> bool {
|
||||||
// Calculate slab intersections
|
// Calculate slab intersections
|
||||||
let t1 = (self.min.co - ray.orig.co) * ray.dir_inv.co;
|
let t1 = (self.min.co - ray.orig.co) * ray.dir_inv.co;
|
||||||
let t2 = (self.max.co - ray.orig.co) * ray.dir_inv.co;
|
let t2 = (self.max.co - ray.orig.co) * ray.dir_inv.co;
|
||||||
|
|
12
src/bvh.rs
12
src/bvh.rs
|
@ -3,7 +3,7 @@
|
||||||
use lerp::lerp_slice;
|
use lerp::lerp_slice;
|
||||||
use bbox::BBox;
|
use bbox::BBox;
|
||||||
use boundable::Boundable;
|
use boundable::Boundable;
|
||||||
use ray::Ray;
|
use ray::{Ray, AccelRay};
|
||||||
use algorithm::partition;
|
use algorithm::partition;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -177,8 +177,8 @@ impl BVH {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn traverse<T, F>(&self, rays: &mut [Ray], objects: &[T], mut obj_ray_test: F)
|
pub fn traverse<T, F>(&self, rays: &mut [AccelRay], objects: &[T], mut obj_ray_test: F)
|
||||||
where F: FnMut(&T, &mut [Ray])
|
where F: FnMut(&T, &mut [AccelRay])
|
||||||
{
|
{
|
||||||
if self.nodes.len() == 0 {
|
if self.nodes.len() == 0 {
|
||||||
return;
|
return;
|
||||||
|
@ -192,14 +192,14 @@ impl BVH {
|
||||||
match self.nodes[i_stack[stack_ptr]] {
|
match self.nodes[i_stack[stack_ptr]] {
|
||||||
BVHNode::Internal { bounds_range: br, second_child_index, split_axis } => {
|
BVHNode::Internal { bounds_range: br, second_child_index, split_axis } => {
|
||||||
let part = partition(&mut rays[..ray_i_stack[stack_ptr]], |r| {
|
let part = partition(&mut rays[..ray_i_stack[stack_ptr]], |r| {
|
||||||
lerp_slice(&self.bounds[br.0..br.1], r.time).intersect_ray(r)
|
lerp_slice(&self.bounds[br.0..br.1], r.time).intersect_accel_ray(r)
|
||||||
});
|
});
|
||||||
if part > 0 {
|
if part > 0 {
|
||||||
i_stack[stack_ptr] += 1;
|
i_stack[stack_ptr] += 1;
|
||||||
i_stack[stack_ptr + 1] = second_child_index;
|
i_stack[stack_ptr + 1] = second_child_index;
|
||||||
ray_i_stack[stack_ptr] = part;
|
ray_i_stack[stack_ptr] = part;
|
||||||
ray_i_stack[stack_ptr + 1] = part;
|
ray_i_stack[stack_ptr + 1] = part;
|
||||||
if rays[0].dir[split_axis as usize].is_sign_positive() {
|
if rays[0].dir_inv[split_axis as usize].is_sign_positive() {
|
||||||
i_stack.swap(stack_ptr, stack_ptr + 1);
|
i_stack.swap(stack_ptr, stack_ptr + 1);
|
||||||
}
|
}
|
||||||
stack_ptr += 1;
|
stack_ptr += 1;
|
||||||
|
@ -210,7 +210,7 @@ impl BVH {
|
||||||
|
|
||||||
BVHNode::Leaf { bounds_range: br, object_range } => {
|
BVHNode::Leaf { bounds_range: br, object_range } => {
|
||||||
let part = partition(&mut rays[..ray_i_stack[stack_ptr]], |r| {
|
let part = partition(&mut rays[..ray_i_stack[stack_ptr]], |r| {
|
||||||
lerp_slice(&self.bounds[br.0..br.1], r.time).intersect_ray(r)
|
lerp_slice(&self.bounds[br.0..br.1], r.time).intersect_accel_ray(r)
|
||||||
});
|
});
|
||||||
if part > 0 {
|
if part > 0 {
|
||||||
for obj in &objects[object_range.0..object_range.1] {
|
for obj in &objects[object_range.0..object_range.1] {
|
||||||
|
|
|
@ -33,7 +33,7 @@ use std::fs::File;
|
||||||
|
|
||||||
use docopt::Docopt;
|
use docopt::Docopt;
|
||||||
|
|
||||||
use ray::Ray;
|
use ray::{Ray, AccelRay};
|
||||||
use parse::{parse_scene, DataTree};
|
use parse::{parse_scene, DataTree};
|
||||||
|
|
||||||
// ----------------------------------------------------------------
|
// ----------------------------------------------------------------
|
||||||
|
@ -92,6 +92,7 @@ fn main() {
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("Ray size: {} bytes", mem::size_of::<Ray>());
|
println!("Ray size: {} bytes", mem::size_of::<Ray>());
|
||||||
|
println!("AccelRay size: {} bytes", mem::size_of::<AccelRay>());
|
||||||
|
|
||||||
// Iterate through scenes and render them
|
// Iterate through scenes and render them
|
||||||
if let DataTree::Internal { ref children, .. } = dt {
|
if let DataTree::Internal { ref children, .. } = dt {
|
||||||
|
|
35
src/ray.rs
35
src/ray.rs
|
@ -9,10 +9,8 @@ use math::{Vector, Point, Matrix4x4};
|
||||||
pub struct Ray {
|
pub struct Ray {
|
||||||
pub orig: Point,
|
pub orig: Point,
|
||||||
pub dir: Vector,
|
pub dir: Vector,
|
||||||
pub dir_inv: Vector,
|
|
||||||
pub max_t: f32,
|
pub max_t: f32,
|
||||||
pub time: f32,
|
pub time: f32,
|
||||||
pub id: u32,
|
|
||||||
pub flags: u32,
|
pub flags: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,10 +19,8 @@ impl Ray {
|
||||||
Ray {
|
Ray {
|
||||||
orig: orig,
|
orig: orig,
|
||||||
dir: dir,
|
dir: dir,
|
||||||
dir_inv: Vector { co: Float4::new(1.0, 1.0, 1.0, 1.0) / dir.co },
|
|
||||||
max_t: std::f32::INFINITY,
|
max_t: std::f32::INFINITY,
|
||||||
time: time,
|
time: time,
|
||||||
id: 0,
|
|
||||||
flags: 0,
|
flags: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,16 +28,39 @@ impl Ray {
|
||||||
pub fn transform(&mut self, mat: &Matrix4x4) {
|
pub fn transform(&mut self, mat: &Matrix4x4) {
|
||||||
self.orig = self.orig * *mat;
|
self.orig = self.orig * *mat;
|
||||||
self.dir = self.dir * *mat;
|
self.dir = self.dir * *mat;
|
||||||
self.dir_inv = Vector { co: Float4::new(1.0, 1.0, 1.0, 1.0) / self.dir.co };
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct AccelRay {
|
||||||
|
pub orig: Point,
|
||||||
|
pub dir_inv: Vector,
|
||||||
|
pub max_t: f32,
|
||||||
|
pub time: f32,
|
||||||
|
pub flags: u32,
|
||||||
|
pub id: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AccelRay {
|
||||||
|
pub fn new(ray: &Ray, id: u32) -> AccelRay {
|
||||||
|
AccelRay {
|
||||||
|
orig: ray.orig,
|
||||||
|
dir_inv: Vector { co: Float4::new(1.0, 1.0, 1.0, 1.0) / ray.dir.co },
|
||||||
|
max_t: ray.max_t,
|
||||||
|
time: ray.time,
|
||||||
|
flags: ray.flags,
|
||||||
|
id: id,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_from_world_ray(&mut self, wr: &Ray) {
|
pub fn update_from_world_ray(&mut self, wr: &Ray) {
|
||||||
self.orig = wr.orig;
|
self.orig = wr.orig;
|
||||||
self.dir = wr.dir;
|
self.dir_inv = Vector { co: Float4::new(1.0, 1.0, 1.0, 1.0) / wr.dir.co };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_from_xformed_world_ray(&mut self, wr: &Ray, mat: &Matrix4x4) {
|
pub fn update_from_xformed_world_ray(&mut self, wr: &Ray, mat: &Matrix4x4) {
|
||||||
self.update_from_world_ray(wr);
|
self.orig = wr.orig * *mat;
|
||||||
self.transform(mat);
|
self.dir_inv = Vector { co: Float4::new(1.0, 1.0, 1.0, 1.0) / (wr.dir * *mat).co };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,6 @@ impl Renderer {
|
||||||
halton::sample(1, offset + si as u32),
|
halton::sample(1, offset + si as u32),
|
||||||
halton::sample(2, offset + si as u32))
|
halton::sample(2, offset + si as u32))
|
||||||
};
|
};
|
||||||
ray.id = rays.len() as u32;
|
|
||||||
rays.push(ray);
|
rays.push(ray);
|
||||||
pixel_mapping.push((x, y))
|
pixel_mapping.push((x, y))
|
||||||
}
|
}
|
||||||
|
@ -120,7 +119,7 @@ impl Renderer {
|
||||||
if let &surface::SurfaceIntersection::Hit { t: _,
|
if let &surface::SurfaceIntersection::Hit { t: _,
|
||||||
pos: _,
|
pos: _,
|
||||||
nor: _,
|
nor: _,
|
||||||
space: _,
|
local_space: _,
|
||||||
uv } = isect {
|
uv } = isect {
|
||||||
|
|
||||||
col.0 += uv.0 / self.spp as f32;
|
col.0 += uv.0 / self.spp as f32;
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::fmt::Debug;
|
||||||
|
|
||||||
pub mod triangle_mesh;
|
pub mod triangle_mesh;
|
||||||
|
|
||||||
use ray::Ray;
|
use ray::{Ray, AccelRay};
|
||||||
use math::{Point, Normal, Matrix4x4};
|
use math::{Point, Normal, Matrix4x4};
|
||||||
use boundable::Boundable;
|
use boundable::Boundable;
|
||||||
|
|
||||||
|
@ -17,11 +17,15 @@ pub enum SurfaceIntersection {
|
||||||
t: f32,
|
t: f32,
|
||||||
pos: Point,
|
pos: Point,
|
||||||
nor: Normal,
|
nor: Normal,
|
||||||
space: Matrix4x4,
|
local_space: Matrix4x4,
|
||||||
uv: (f32, f32),
|
uv: (f32, f32),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Surface: Boundable + Debug + Sync {
|
pub trait Surface: Boundable + Debug + Sync {
|
||||||
fn intersect_rays(&self, rays: &mut [Ray], isects: &mut [SurfaceIntersection]);
|
fn intersect_rays(&self,
|
||||||
|
accel_rays: &mut [AccelRay],
|
||||||
|
wrays: &[Ray],
|
||||||
|
isects: &mut [SurfaceIntersection],
|
||||||
|
space: &[Matrix4x4]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use lerp::{lerp, lerp_slice_with};
|
use lerp::{lerp, lerp_slice, lerp_slice_with};
|
||||||
use math::{Point, Normal, Matrix4x4};
|
use math::{Point, Normal, Matrix4x4};
|
||||||
use ray::Ray;
|
use ray::{Ray, AccelRay};
|
||||||
use triangle;
|
use triangle;
|
||||||
use bbox::BBox;
|
use bbox::BBox;
|
||||||
use boundable::Boundable;
|
use boundable::Boundable;
|
||||||
|
@ -59,22 +59,30 @@ impl Boundable for TriangleMesh {
|
||||||
|
|
||||||
|
|
||||||
impl Surface for TriangleMesh {
|
impl Surface for TriangleMesh {
|
||||||
fn intersect_rays(&self, rays: &mut [Ray], isects: &mut [SurfaceIntersection]) {
|
fn intersect_rays(&self,
|
||||||
self.accel.traverse(&mut rays[..], &self.indices, |tri_i, rs| {
|
accel_rays: &mut [AccelRay],
|
||||||
|
wrays: &[Ray],
|
||||||
|
isects: &mut [SurfaceIntersection],
|
||||||
|
space: &[Matrix4x4]) {
|
||||||
|
self.accel.traverse(&mut accel_rays[..], &self.indices, |tri_i, rs| {
|
||||||
for r in rs {
|
for r in rs {
|
||||||
|
let wr = &wrays[r.id as usize];
|
||||||
let tri =
|
let tri =
|
||||||
lerp_slice_with(&self.geo[*tri_i..(*tri_i + self.time_samples)],
|
lerp_slice_with(&self.geo[*tri_i..(*tri_i + self.time_samples)],
|
||||||
r.time,
|
wr.time,
|
||||||
|a, b, t| {
|
|a, b, t| {
|
||||||
(lerp(a.0, b.0, t), lerp(a.1, b.1, t), lerp(a.2, b.2, t))
|
(lerp(a.0, b.0, t), lerp(a.1, b.1, t), lerp(a.2, b.2, t))
|
||||||
});
|
});
|
||||||
if let Some((t, tri_u, tri_v)) = triangle::intersect_ray(r, tri) {
|
let mat_space = lerp_slice(space, wr.time);
|
||||||
|
let mat_inv = mat_space.inverse();
|
||||||
|
let tri = (tri.0 * mat_inv, tri.1 * mat_inv, tri.2 * mat_inv);
|
||||||
|
if let Some((t, tri_u, tri_v)) = triangle::intersect_ray(wr, tri) {
|
||||||
if t < r.max_t {
|
if t < r.max_t {
|
||||||
isects[r.id as usize] = SurfaceIntersection::Hit {
|
isects[r.id as usize] = SurfaceIntersection::Hit {
|
||||||
t: t,
|
t: t,
|
||||||
pos: r.orig + (r.dir * t),
|
pos: wr.orig + (wr.dir * t),
|
||||||
nor: Normal::new(0.0, 0.0, 0.0), // TODO
|
nor: Normal::new(0.0, 0.0, 0.0), // TODO
|
||||||
space: Matrix4x4::new(), // TODO
|
local_space: mat_space,
|
||||||
uv: (tri_u, tri_v),
|
uv: (tri_u, tri_v),
|
||||||
};
|
};
|
||||||
r.max_t = t;
|
r.max_t = t;
|
||||||
|
|
|
@ -4,12 +4,12 @@ use std::cell::UnsafeCell;
|
||||||
use math::{Matrix4x4, multiply_matrix_slices};
|
use math::{Matrix4x4, multiply_matrix_slices};
|
||||||
use lerp::lerp_slice;
|
use lerp::lerp_slice;
|
||||||
use assembly::{Assembly, Object, InstanceType};
|
use assembly::{Assembly, Object, InstanceType};
|
||||||
use ray::Ray;
|
use ray::{Ray, AccelRay};
|
||||||
use surface::SurfaceIntersection;
|
use surface::SurfaceIntersection;
|
||||||
|
|
||||||
pub struct Tracer<'a> {
|
pub struct Tracer<'a> {
|
||||||
root: &'a Assembly,
|
root: &'a Assembly,
|
||||||
rays: UnsafeCell<Vec<Ray>>, // Should only be used from trace(), not any other methods
|
rays: UnsafeCell<Vec<AccelRay>>, // Should only be used from trace(), not any other methods
|
||||||
xform_stack: TransformStack,
|
xform_stack: TransformStack,
|
||||||
isects: Vec<SurfaceIntersection>,
|
isects: Vec<SurfaceIntersection>,
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,8 @@ impl<'a> Tracer<'a> {
|
||||||
unsafe {
|
unsafe {
|
||||||
(*rays_ptr).clear();
|
(*rays_ptr).clear();
|
||||||
(*rays_ptr).reserve(wrays.len());
|
(*rays_ptr).reserve(wrays.len());
|
||||||
(*rays_ptr).extend(wrays.iter());
|
let mut ids = 0..(wrays.len() as u32);
|
||||||
|
(*rays_ptr).extend(wrays.iter().map(|wr| AccelRay::new(wr, ids.next().unwrap())));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ready the isects
|
// Ready the isects
|
||||||
|
@ -55,8 +56,11 @@ impl<'a> Tracer<'a> {
|
||||||
return &self.isects;
|
return &self.isects;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trace_assembly<'b>(&'b mut self, assembly: &Assembly, wrays: &[Ray], rays: &mut [Ray]) {
|
fn trace_assembly<'b>(&'b mut self,
|
||||||
assembly.object_accel.traverse(&mut rays[..], &assembly.instances[..], |inst, rs| {
|
assembly: &Assembly,
|
||||||
|
wrays: &[Ray],
|
||||||
|
accel_rays: &mut [AccelRay]) {
|
||||||
|
assembly.object_accel.traverse(&mut accel_rays[..], &assembly.instances[..], |inst, rs| {
|
||||||
// Transform rays if needed
|
// Transform rays if needed
|
||||||
if let Some((xstart, xend)) = inst.transform_indices {
|
if let Some((xstart, xend)) = inst.transform_indices {
|
||||||
// Push transforms to stack
|
// Push transforms to stack
|
||||||
|
@ -106,10 +110,10 @@ impl<'a> Tracer<'a> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trace_object<'b>(&'b mut self, obj: &Object, wrays: &[Ray], rays: &mut [Ray]) {
|
fn trace_object<'b>(&'b mut self, obj: &Object, wrays: &[Ray], rays: &mut [AccelRay]) {
|
||||||
match obj {
|
match obj {
|
||||||
&Object::Surface(ref surface) => {
|
&Object::Surface(ref surface) => {
|
||||||
surface.intersect_rays(rays, &mut self.isects);
|
surface.intersect_rays(rays, wrays, &mut self.isects, self.xform_stack.top());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user