Draw first real image
This commit is contained in:
parent
62b9fdcb56
commit
50d3874467
16 changed files with 565 additions and 56 deletions
49
ray-tracing-scene/src/basic_scene.rs
Normal file
49
ray-tracing-scene/src/basic_scene.rs
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
use rand::Rng;
|
||||
use ray_tracing_core::material::DefaultMaterial;
|
||||
use ray_tracing_core::prelude::*;
|
||||
use ray_tracing_core::scene::{Intersection, Scene};
|
||||
|
||||
pub struct BasicScene {
|
||||
pub(crate) spheres: Vec<(Pos3, Float)>,
|
||||
}
|
||||
|
||||
impl BasicScene {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
spheres: vec![(Pos3::zero(), 1.0), (Pos3::new(0.0, 0.0, 2.5), 2.0)],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Rng> Scene<R> for BasicScene {
|
||||
fn intersect(&self, ray: Ray, min: Float, max: Float) -> Option<Intersection<'_, R>> {
|
||||
let mut intersection: Option<Intersection<'_, R>> = None;
|
||||
|
||||
for &(c, r) in &self.spheres {
|
||||
let offset = ray.start() - c;
|
||||
let p = Dir3::dot(ray.dir(), offset);
|
||||
let delta = p * p - (offset.length_squared() - r * r);
|
||||
|
||||
if delta >= 0.0 {
|
||||
let d = -p - Float::sqrt(delta);
|
||||
|
||||
let int = Intersection::new(
|
||||
d,
|
||||
((ray.start() + d * ray.dir()) - c).normalize(),
|
||||
&DefaultMaterial {},
|
||||
);
|
||||
if d >= min && d <= max {
|
||||
if let Some(i) = intersection.as_ref() {
|
||||
if i.t() > d {
|
||||
intersection.replace(int);
|
||||
}
|
||||
} else {
|
||||
intersection = Some(int)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
intersection
|
||||
}
|
||||
}
|
||||
|
|
@ -1,51 +1,7 @@
|
|||
use rand::Rng;
|
||||
use ray_tracing_core::material::DefaultMaterial;
|
||||
use ray_tracing_core::prelude::*;
|
||||
use ray_tracing_core::scene::{Intersection, Scene};
|
||||
|
||||
pub mod sphere;
|
||||
pub mod basic_scene;
|
||||
|
||||
pub struct BasicScene {
|
||||
spheres: Vec<(Pos3, Float)>,
|
||||
}
|
||||
|
||||
impl BasicScene {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
spheres: vec![(Pos3::zero(), 1.0), (Pos3::new(0.0, 0.0, 2.5), 2.0)],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Rng> Scene<R> for BasicScene {
|
||||
fn intersect(&self, ray: Ray, min: Float, max: Float) -> Option<Intersection<'_, R>> {
|
||||
let mut intersection: Option<Intersection<'_, R>> = None;
|
||||
|
||||
for &(c, r) in &self.spheres {
|
||||
let offset = ray.start() - c;
|
||||
let p = Dir3::dot(ray.dir(), offset);
|
||||
let delta = p * p - (offset.length_squared() - r * r);
|
||||
|
||||
if delta >= 0.0 {
|
||||
let d = -p - Float::sqrt(delta);
|
||||
|
||||
let int = Intersection::new(
|
||||
d,
|
||||
((ray.start() + d * ray.dir()) - c).normalize(),
|
||||
&DefaultMaterial {},
|
||||
);
|
||||
if d >= min && d <= max {
|
||||
if let Some(i) = intersection.as_ref() {
|
||||
if i.t() > d {
|
||||
intersection.replace(int);
|
||||
}
|
||||
} else {
|
||||
intersection = Some(int)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
intersection
|
||||
}
|
||||
}
|
||||
pub mod triangle_bvh;
|
||||
|
|
|
|||
206
ray-tracing-scene/src/triangle_bvh.rs
Normal file
206
ray-tracing-scene/src/triangle_bvh.rs
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
use rand::Rng;
|
||||
use ray_tracing_core::{
|
||||
prelude::*,
|
||||
scene::{Intersection, Scene},
|
||||
};
|
||||
|
||||
type Index = u32;
|
||||
|
||||
pub struct TriangleBVH<R: Rng> {
|
||||
vertices: Vec<Pos3>,
|
||||
triangles: Vec<Triangle>,
|
||||
materials: Vec<Box<dyn Material<R>>>,
|
||||
bvh: Vec<Node>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum Node {
|
||||
Inner {
|
||||
left: Index,
|
||||
left_aabb: AABB,
|
||||
right: Index,
|
||||
right_aabb: AABB,
|
||||
},
|
||||
Leaf {
|
||||
start: Index,
|
||||
count: Index,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Triangle {
|
||||
vertices: [Index; 3],
|
||||
material: Index,
|
||||
}
|
||||
|
||||
impl Triangle {
|
||||
fn new(vertices: [Index; 3], material: Index) -> Self {
|
||||
Triangle { vertices, material }
|
||||
}
|
||||
}
|
||||
|
||||
fn triangle_intersection(ray: Ray, v: [Pos3; 3]) -> Option<Float> {
|
||||
let e1 = v[1] - v[0];
|
||||
let e2 = v[2] - v[0];
|
||||
|
||||
let ray_cross_e2 = Dir3::cross(ray.dir(), e2);
|
||||
let det = e1.dot(ray_cross_e2);
|
||||
|
||||
if det > -f32::EPSILON && det < f32::EPSILON {
|
||||
return None; // This ray is parallel to this triangle.
|
||||
}
|
||||
|
||||
let inv_det = 1.0 / det;
|
||||
let s = ray.start() - v[0];
|
||||
let u = inv_det * s.dot(ray_cross_e2);
|
||||
if u < 0.0 || u > 1.0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let s_cross_e1 = s.cross(e1);
|
||||
let v = inv_det * Dir3::dot(ray.dir(), s_cross_e1);
|
||||
if v < 0.0 || u + v > 1.0 {
|
||||
return None;
|
||||
}
|
||||
// At this stage we can compute t to find out where the intersection point is on the line.
|
||||
let t = inv_det * e2.dot(s_cross_e1);
|
||||
|
||||
if t > Float::EPSILON {
|
||||
// ray intersection
|
||||
Some(t)
|
||||
} else {
|
||||
// This means that there is a line intersection but not a ray intersection.
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn triangle_normal(v: [Pos3; 3]) -> Dir3 {
|
||||
let e1 = v[1] - v[0];
|
||||
let e2 = v[2] - v[0];
|
||||
|
||||
Dir3::cross(e1, e2)
|
||||
}
|
||||
|
||||
impl<R: Rng> TriangleBVH<R> {
|
||||
fn new(
|
||||
vertices: Vec<Pos3>,
|
||||
triangles: Vec<Triangle>,
|
||||
materials: Vec<Box<dyn Material<R>>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
vertices,
|
||||
bvh: vec![Node::Leaf {
|
||||
start: 0,
|
||||
count: triangles.len() as Index,
|
||||
}],
|
||||
triangles,
|
||||
materials,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_vertices(&self, triangle: Index) -> [Pos3; 3] {
|
||||
let t = self.triangles[triangle as usize];
|
||||
[
|
||||
self.vertices[t.vertices[0] as usize],
|
||||
self.vertices[t.vertices[1] as usize],
|
||||
self.vertices[t.vertices[2] as usize],
|
||||
]
|
||||
}
|
||||
|
||||
fn intersect_bvh(
|
||||
&self,
|
||||
node: Index,
|
||||
ray: Ray,
|
||||
min: Float,
|
||||
max: Float,
|
||||
) -> Option<(Index, Float)> {
|
||||
match self.bvh[node as usize] {
|
||||
Node::Inner {
|
||||
left,
|
||||
left_aabb,
|
||||
right,
|
||||
right_aabb,
|
||||
} => todo!(),
|
||||
Node::Leaf { start, count } => {
|
||||
let mut intersection = None;
|
||||
for i in start..(start + count) {
|
||||
if let Some(t) = triangle_intersection(ray, self.get_vertices(i)) {
|
||||
if min <= t && t <= max && !intersection.is_some_and(|(_, old_t)| t > old_t)
|
||||
{
|
||||
intersection.replace((i, t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
intersection
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Rng> Scene<R> for TriangleBVH<R> {
|
||||
fn intersect(
|
||||
&self,
|
||||
ray: Ray,
|
||||
min: Float,
|
||||
max: Float,
|
||||
) -> Option<ray_tracing_core::scene::Intersection<'_, R>> {
|
||||
let (i, t) = self.intersect_bvh(0, ray, min, max)?;
|
||||
|
||||
let triangle = self.triangles[i as usize];
|
||||
let material = self.materials[triangle.material as usize].as_ref();
|
||||
|
||||
let n = triangle_normal(self.get_vertices(i)).normalize();
|
||||
|
||||
Some(Intersection::new(t, n, material))
|
||||
}
|
||||
}
|
||||
|
||||
pub mod examples {
|
||||
use super::{Triangle, TriangleBVH};
|
||||
use rand::Rng;
|
||||
use ray_tracing_core::material::{AreaLight, DiffuseMaterial};
|
||||
use ray_tracing_core::prelude::*;
|
||||
|
||||
pub fn cornel<R: Rng>() -> TriangleBVH<R> {
|
||||
let side_length = 1.5;
|
||||
let light_size = 0.5;
|
||||
let light_offset = 0.01;
|
||||
TriangleBVH::new(
|
||||
vec![
|
||||
Pos3::new(side_length, side_length, side_length),
|
||||
Pos3::new(side_length, side_length, -side_length),
|
||||
Pos3::new(side_length, -side_length, side_length),
|
||||
Pos3::new(side_length, -side_length, -side_length),
|
||||
Pos3::new(-side_length, side_length, side_length),
|
||||
Pos3::new(-side_length, side_length, -side_length),
|
||||
Pos3::new(-side_length, -side_length, side_length),
|
||||
Pos3::new(-side_length, -side_length, -side_length),
|
||||
Pos3::new(light_size, side_length - light_offset, light_size),
|
||||
Pos3::new(light_size, side_length - light_offset, -light_size),
|
||||
Pos3::new(-light_size, side_length - light_offset, light_size),
|
||||
Pos3::new(-light_size, side_length - light_offset, -light_size),
|
||||
],
|
||||
vec![
|
||||
Triangle::new([0, 1, 2], 0),
|
||||
Triangle::new([1, 3, 2], 0),
|
||||
Triangle::new([0, 4, 1], 0),
|
||||
Triangle::new([1, 4, 5], 0),
|
||||
Triangle::new([2, 3, 6], 0),
|
||||
Triangle::new([3, 7, 6], 0),
|
||||
Triangle::new([0, 2, 4], 1),
|
||||
Triangle::new([6, 4, 2], 1),
|
||||
Triangle::new([1, 5, 3], 2),
|
||||
Triangle::new([7, 3, 5], 2),
|
||||
Triangle::new([8, 10, 9], 3),
|
||||
Triangle::new([11, 9, 10], 3),
|
||||
],
|
||||
vec![
|
||||
Box::new(DiffuseMaterial::new(Color::new(0.8, 0.8, 0.8))),
|
||||
Box::new(DiffuseMaterial::new(Color::new(0.9, 0.0, 0.0))),
|
||||
Box::new(DiffuseMaterial::new(Color::new(0.0, 0.9, 0.0))),
|
||||
Box::new(AreaLight::new(Color::new(5.0, 5.0, 5.0))),
|
||||
],
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue