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 lerp::{lerp, lerp_slice, Lerp};
|
||||
use ray::Ray;
|
||||
use ray::AccelRay;
|
||||
|
||||
const BBOX_MAXT_ADJUST: f32 = 1.00000024;
|
||||
|
||||
|
@ -38,7 +38,7 @@ impl 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
|
||||
let t1 = (self.min.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 bbox::BBox;
|
||||
use boundable::Boundable;
|
||||
use ray::Ray;
|
||||
use ray::{Ray, AccelRay};
|
||||
use algorithm::partition;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -177,8 +177,8 @@ impl BVH {
|
|||
}
|
||||
|
||||
|
||||
pub fn traverse<T, F>(&self, rays: &mut [Ray], objects: &[T], mut obj_ray_test: F)
|
||||
where F: FnMut(&T, &mut [Ray])
|
||||
pub fn traverse<T, F>(&self, rays: &mut [AccelRay], objects: &[T], mut obj_ray_test: F)
|
||||
where F: FnMut(&T, &mut [AccelRay])
|
||||
{
|
||||
if self.nodes.len() == 0 {
|
||||
return;
|
||||
|
@ -192,14 +192,14 @@ impl BVH {
|
|||
match self.nodes[i_stack[stack_ptr]] {
|
||||
BVHNode::Internal { bounds_range: br, second_child_index, split_axis } => {
|
||||
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 {
|
||||
i_stack[stack_ptr] += 1;
|
||||
i_stack[stack_ptr + 1] = second_child_index;
|
||||
ray_i_stack[stack_ptr] = 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);
|
||||
}
|
||||
stack_ptr += 1;
|
||||
|
@ -210,7 +210,7 @@ impl BVH {
|
|||
|
||||
BVHNode::Leaf { bounds_range: br, object_range } => {
|
||||
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 {
|
||||
for obj in &objects[object_range.0..object_range.1] {
|
||||
|
|
|
@ -33,7 +33,7 @@ use std::fs::File;
|
|||
|
||||
use docopt::Docopt;
|
||||
|
||||
use ray::Ray;
|
||||
use ray::{Ray, AccelRay};
|
||||
use parse::{parse_scene, DataTree};
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
|
@ -92,6 +92,7 @@ fn main() {
|
|||
};
|
||||
|
||||
println!("Ray size: {} bytes", mem::size_of::<Ray>());
|
||||
println!("AccelRay size: {} bytes", mem::size_of::<AccelRay>());
|
||||
|
||||
// Iterate through scenes and render them
|
||||
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 orig: Point,
|
||||
pub dir: Vector,
|
||||
pub dir_inv: Vector,
|
||||
pub max_t: f32,
|
||||
pub time: f32,
|
||||
pub id: u32,
|
||||
pub flags: u32,
|
||||
}
|
||||
|
||||
|
@ -21,10 +19,8 @@ impl Ray {
|
|||
Ray {
|
||||
orig: orig,
|
||||
dir: dir,
|
||||
dir_inv: Vector { co: Float4::new(1.0, 1.0, 1.0, 1.0) / dir.co },
|
||||
max_t: std::f32::INFINITY,
|
||||
time: time,
|
||||
id: 0,
|
||||
flags: 0,
|
||||
}
|
||||
}
|
||||
|
@ -32,16 +28,39 @@ impl Ray {
|
|||
pub fn transform(&mut self, mat: &Matrix4x4) {
|
||||
self.orig = self.orig * *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) {
|
||||
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) {
|
||||
self.update_from_world_ray(wr);
|
||||
self.transform(mat);
|
||||
self.orig = wr.orig * *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(2, offset + si as u32))
|
||||
};
|
||||
ray.id = rays.len() as u32;
|
||||
rays.push(ray);
|
||||
pixel_mapping.push((x, y))
|
||||
}
|
||||
|
@ -120,7 +119,7 @@ impl Renderer {
|
|||
if let &surface::SurfaceIntersection::Hit { t: _,
|
||||
pos: _,
|
||||
nor: _,
|
||||
space: _,
|
||||
local_space: _,
|
||||
uv } = isect {
|
||||
|
||||
col.0 += uv.0 / self.spp as f32;
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::fmt::Debug;
|
|||
|
||||
pub mod triangle_mesh;
|
||||
|
||||
use ray::Ray;
|
||||
use ray::{Ray, AccelRay};
|
||||
use math::{Point, Normal, Matrix4x4};
|
||||
use boundable::Boundable;
|
||||
|
||||
|
@ -17,11 +17,15 @@ pub enum SurfaceIntersection {
|
|||
t: f32,
|
||||
pos: Point,
|
||||
nor: Normal,
|
||||
space: Matrix4x4,
|
||||
local_space: Matrix4x4,
|
||||
uv: (f32, f32),
|
||||
},
|
||||
}
|
||||
|
||||
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)]
|
||||
|
||||
use lerp::{lerp, lerp_slice_with};
|
||||
use lerp::{lerp, lerp_slice, lerp_slice_with};
|
||||
use math::{Point, Normal, Matrix4x4};
|
||||
use ray::Ray;
|
||||
use ray::{Ray, AccelRay};
|
||||
use triangle;
|
||||
use bbox::BBox;
|
||||
use boundable::Boundable;
|
||||
|
@ -59,22 +59,30 @@ impl Boundable for TriangleMesh {
|
|||
|
||||
|
||||
impl Surface for TriangleMesh {
|
||||
fn intersect_rays(&self, rays: &mut [Ray], isects: &mut [SurfaceIntersection]) {
|
||||
self.accel.traverse(&mut rays[..], &self.indices, |tri_i, rs| {
|
||||
fn intersect_rays(&self,
|
||||
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 {
|
||||
let wr = &wrays[r.id as usize];
|
||||
let tri =
|
||||
lerp_slice_with(&self.geo[*tri_i..(*tri_i + self.time_samples)],
|
||||
r.time,
|
||||
wr.time,
|
||||
|a, b, 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 {
|
||||
isects[r.id as usize] = SurfaceIntersection::Hit {
|
||||
t: t,
|
||||
pos: r.orig + (r.dir * t),
|
||||
pos: wr.orig + (wr.dir * t),
|
||||
nor: Normal::new(0.0, 0.0, 0.0), // TODO
|
||||
space: Matrix4x4::new(), // TODO
|
||||
local_space: mat_space,
|
||||
uv: (tri_u, tri_v),
|
||||
};
|
||||
r.max_t = t;
|
||||
|
|
|
@ -4,12 +4,12 @@ use std::cell::UnsafeCell;
|
|||
use math::{Matrix4x4, multiply_matrix_slices};
|
||||
use lerp::lerp_slice;
|
||||
use assembly::{Assembly, Object, InstanceType};
|
||||
use ray::Ray;
|
||||
use ray::{Ray, AccelRay};
|
||||
use surface::SurfaceIntersection;
|
||||
|
||||
pub struct Tracer<'a> {
|
||||
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,
|
||||
isects: Vec<SurfaceIntersection>,
|
||||
}
|
||||
|
@ -30,7 +30,8 @@ impl<'a> Tracer<'a> {
|
|||
unsafe {
|
||||
(*rays_ptr).clear();
|
||||
(*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
|
||||
|
@ -55,8 +56,11 @@ impl<'a> Tracer<'a> {
|
|||
return &self.isects;
|
||||
}
|
||||
|
||||
fn trace_assembly<'b>(&'b mut self, assembly: &Assembly, wrays: &[Ray], rays: &mut [Ray]) {
|
||||
assembly.object_accel.traverse(&mut rays[..], &assembly.instances[..], |inst, rs| {
|
||||
fn trace_assembly<'b>(&'b mut self,
|
||||
assembly: &Assembly,
|
||||
wrays: &[Ray],
|
||||
accel_rays: &mut [AccelRay]) {
|
||||
assembly.object_accel.traverse(&mut accel_rays[..], &assembly.instances[..], |inst, rs| {
|
||||
// Transform rays if needed
|
||||
if let Some((xstart, xend)) = inst.transform_indices {
|
||||
// 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 {
|
||||
&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