-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSphere.cpp
More file actions
94 lines (77 loc) · 2.47 KB
/
Sphere.cpp
File metadata and controls
94 lines (77 loc) · 2.47 KB
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
/* $Rev: 250 $ */
#include "Sphere.h"
#include "utility.h"
Sphere::Sphere() : Object() {
}
Sphere::Sphere(const Sphere& sphere) : Object(sphere) {
}
Sphere::~Sphere() {
}
const Sphere& Sphere::operator=(const Sphere& sphere) {
if (this != &sphere) {
Object::operator=(sphere);
}
return *this;
}
std::vector<RayIntersection> Sphere::intersect(const Ray& ray) const {
std::vector<RayIntersection> result;
Ray inverseRay = transform.applyInverse(ray);
// Intersection is of the form ad^2 + bd + c, where d = distance along the ray
double a = inverseRay.direction.squaredNorm();
double b = 2*inverseRay.direction.dot(inverseRay.point);
double c = inverseRay.point.squaredNorm() - 1;
RayIntersection hit;
hit.material = material;
double b2_4ac = b*b - 4*a*c;
double d;
switch (sign(b2_4ac)) {
case -1:
// No intersections
break;
case 0:
// One intersection
d = -b/(2*a);
if (d > 0) {
// Intersection is in front of the ray's start point
hit.point = transform.apply(Point(inverseRay.point + d*inverseRay.direction));
hit.normal = transform.apply(Normal(inverseRay.point + d*inverseRay.direction));
if (hit.normal.dot(ray.direction) > 0) {
hit.normal = -hit.normal;
}
hit.distance = (hit.point - ray.point).norm() * sign(d);
result.push_back(hit);
}
break;
case 1:
// Two intersections
d = (-b + sqrt(b*b - 4*a*c))/(2*a);
if (d > 0) {
// Intersection is in front of the ray's start point
hit.point = transform.apply(Point(inverseRay.point + d*inverseRay.direction));
hit.normal = transform.apply(Normal(inverseRay.point + d*inverseRay.direction));
if (hit.normal.dot(ray.direction) > 0) {
hit.normal = -hit.normal;
}
hit.distance = (hit.point - ray.point).norm() * sign(d);
result.push_back(hit);
}
d = (-b - sqrt(b*b - 4*a*c))/(2*a);
if (d > 0) {
// Intersection is in front of the ray's start point
hit.point = transform.apply(Point(inverseRay.point + d*inverseRay.direction));
hit.normal = transform.apply(Normal(inverseRay.point + d*inverseRay.direction));
if (hit.normal.dot(ray.direction) > 0) {
hit.normal = -hit.normal;
}
hit.distance = (hit.point - ray.point).norm() * sign(d);
result.push_back(hit);
}
break;
default:
// Shouldn't be possible, but just in case
std::cerr << "Something's wrong - sign(x) should be -1, +1 or 0" << std::endl;
exit(-1);
break;
}
return result;
}