1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
use bsdf::BSDF;
use intersection::Intersection;
use material::Material;
use plane::Plane;
use ray::Ray;
use rectangle::Rectangle;
use sphere::Sphere;
use triangle::Triangle;
use std;

use cgmath::prelude::*;
extern crate cgmath;
type Float3 = cgmath::Vector3<f64>;

//#[derive(Copy, Clone)]
pub struct Scene {
    pub spheres: Vec<Sphere>,
    pub planes: Vec<Plane>,
    pub rectangles: Vec<Rectangle>,
    pub triangles: Vec<Triangle>,
}

impl Scene {
    pub fn new(spheres: Vec<Sphere>, planes: Vec<Plane>, rectangles: Vec<Rectangle>, triangles: Vec<Triangle>) -> Scene {
        Scene {
            spheres: spheres,
            planes: planes,
            rectangles: rectangles,
            triangles: triangles,
        }
    }

    pub fn intersect(&self, ray: Ray) -> Option<(Intersection, f64)> {
        let mut result = (0, std::f64::INFINITY);
        let mut intersection_position = Float3::zero();
        let mut intersection_normal = Float3::zero();
        let mut intersection_material = Material::black();

        // Intersect Spheres
        for s in 0..self.spheres.len() {
            let sphere = &self.spheres[s];
            let hit_t = sphere.intersect(ray);
            let (_, prev_t) = result;

            if hit_t < prev_t && hit_t > 1e-6 {
                result = (s, hit_t);

                intersection_position = self.spheres[s].position;

                let position = ray.origin + ray.direction * hit_t;
                intersection_normal = (position - intersection_position).normalize();
                intersection_normal = if Float3::dot(intersection_normal, ray.direction) < 0.0 {
                    intersection_normal
                } else {
                    intersection_normal * -1.0
                };

                intersection_material = self.spheres[s].material;
            }
        }

        // Intersect Planes
        for s in 0..self.planes.len() {
            let plane = &self.planes[s];
            let hit_t = plane.intersect(ray);
            let (_, prev_t) = result;

            if hit_t < prev_t && hit_t > 1e-6 {
                result = (s, hit_t);

                let position = ray.origin + ray.direction * hit_t;
                intersection_position =  position;

                intersection_normal = if Float3::dot(plane.normal, ray.direction) < 0.0 {
                    plane.normal
                } else {
                    plane.normal * -1.0
                };

                intersection_material = plane.material;
            }
        }

        // Intersect Rectangles
        for s in 0..self.rectangles.len() {
            let rectangle = &self.rectangles[s];
            let hit_t = rectangle.intersect(ray);
            let (_, prev_t) = result;

            if hit_t < prev_t && hit_t > 1e-6 {
                result = (s, hit_t);

                let position = ray.origin + ray.direction * hit_t;
                intersection_position =  position;

                intersection_normal = if Float3::dot(rectangle.normal, ray.direction) < 0.0 {
                    rectangle.normal
                } else {
                    rectangle.normal * -1.0
                };

                intersection_material = rectangle.material;
            }
        }

        // Intersect Triangles
        for s in 0..self.triangles.len() {
            let triangle = &self.triangles[s];
            let hit_t = triangle.intersect(ray);
            let (_, prev_t) = result;

            if hit_t < prev_t && hit_t > 1e-6 {
                result = (s, hit_t);

                let position = ray.origin + ray.direction * hit_t;
                intersection_position =  position;

                intersection_normal = if Float3::dot(triangle.normal, ray.direction) < 0.0 {
                    triangle.normal
                } else {
                    triangle.normal * -1.0
                };

                intersection_material = triangle.material;
            }
        }        

        let (_, hit_t) = result;
        if hit_t != std::f64::INFINITY {
            Some((
                Intersection::new(
                    intersection_position,
                    intersection_normal,
                    intersection_material,
                ),
                hit_t,
            ))
        } else {
            None
        }
    }
}