-
Notifications
You must be signed in to change notification settings - Fork 3
/
triangle.cc
110 lines (83 loc) · 3.01 KB
/
triangle.cc
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
// triangle.cc
#include "triangle.h"
Triangle::Triangle(const Vector3& _p0, const Vector3& _p1, \
const Vector3& _p2, const rgb& _color)
: p0(_p0), p1(_p1), p2(_p2), color(_color)
{ }
// using barycentric coordinates (a,b,c):
// p(aplha, beta, gamma) = alpha*a + beta*b + gamma*c
// with alpha+beta+gamma=1
// as alpha|beta|gamma all are wihtin (0,1)
// alpha = 1 - beta - gamma
// and therefore
// p(beta, gamma) = a + beta(b-a) + gamma(c-a)
// and p(beta, gamma) == p(t) == o + td
// if expanded to 3 equations for vector (x,y,z) we get a 3x3 linear system
// that is solved using Cramer's rule
//
// the normal vector of a triangle is the cross product (x) of
// two vectors in the pane and if we stick to store these vectors
// counterclockwise:
// n = (b-a) x (c-a)
bool Triangle::hit(const Ray& r, float tmin, float tmax, float time, \
HitRecord& record) const {
float A = p0.x() - p1.x();
float B = p0.y() - p1.y();
float C = p0.z() - p1.z();
float D = p0.x() - p2.x();
float E = p0.y() - p2.y();
float F = p0.z() - p2.z();
float G = r.direction().x();
float H = r.direction().y();
float I = r.direction().z();
float J = p0.x() - r.origin().x();
float K = p0.y() - r.origin().y();
float L = p0.z() - r.origin().z();
float EIHF = E*I - H*F;
float GFDI = G*F - D*I;
float DHEG = D*H - E*G;
float denom = (A*EIHF + B*GFDI + C*DHEG);
float beta = (J*EIHF + K*GFDI + L*DHEG) / denom;
if (beta <= 0.0f || beta >= 1.0f) return false;
float AKJB = A*K - J*B;
float JCAL = J*C - A*L;
float BLKC = B*L - K*C;
float gamma = (I*AKJB + H*JCAL + G*BLKC) / denom;
if (gamma <= 0.0f || beta + gamma >= 1.0f) return false;
float tval = -(F*AKJB + E*JCAL + D*BLKC) / denom;
if (tval >= tmin && tval <= tmax) {
record.t = tval;
record.normal = unitVector(cross((p1 - p0), (p2 - p0)));
record.color = color;
return true;
}
return false;
}
bool Triangle::shadowHit(const Ray& r, float tmin, float tmax, \
float time) const {
float A = p0.x() - p1.x();
float B = p0.y() - p1.y();
float C = p0.z() - p1.z();
float D = p0.x() - p2.x();
float E = p0.y() - p2.y();
float F = p0.z() - p2.z();
float G = r.direction().x();
float H = r.direction().y();
float I = r.direction().z();
float J = p0.x() - r.origin().x();
float K = p0.y() - r.origin().y();
float L = p0.z() - r.origin().z();
float EIHF = E*I - H*F;
float GFDI = G*F - D*I;
float DHEG = D*H - E*G;
float denom = (A*EIHF + B*GFDI + C*DHEG);
float beta = (J*EIHF + K*GFDI + L*DHEG) / denom;
if (beta <= 0.0f || beta >= 1.0f) return false;
float AKJB = A*K - J*B;
float JCAL = J*C - A*L;
float BLKC = B*L - K*C;
float gamma = (I*AKJB + H*JCAL + G*BLKC) / denom;
if (gamma <= 0.0f || beta + gamma >= 1.0f) return false;
float tval = -(F*AKJB + E*JCAL + D*BLKC) / denom;
return (tval >= tmin && tval <= tmax);
}