1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "Math/BsRay.h"
4#include "Math/BsPlane.h"
5#include "Math/BsSphere.h"
6#include "Math/BsAABox.h"
7#include "Math/BsMath.h"
8
9namespace bs
10{
11 void Ray::transform(const Matrix4& matrix)
12 {
13 Vector3 end = getPoint(1.0f);
14
15 mOrigin = matrix.multiply(mOrigin);
16 end = matrix.multiply(end);
17
18 mDirection = Vector3::normalize(end - mOrigin);
19 }
20
21 void Ray::transformAffine(const Matrix4& matrix)
22 {
23 Vector3 end = getPoint(1.0f);
24
25 mOrigin = matrix.multiplyAffine(mOrigin);
26 end = matrix.multiplyAffine(end);
27
28 mDirection = Vector3::normalize(end - mOrigin);
29 }
30
31 std::pair<bool, float> Ray::intersects(const Plane& p) const
32 {
33 return p.intersects(*this);
34 }
35
36 std::pair<bool, float> Ray::intersects(const Sphere& s) const
37 {
38 return s.intersects(*this);
39 }
40
41 std::pair<bool, float> Ray::intersects(const AABox& box) const
42 {
43 return box.intersects(*this);
44 }
45
46 std::pair<bool, float> Ray::intersects(const Vector3& a,
47 const Vector3& b, const Vector3& c, const Vector3& normal,
48 bool positiveSide, bool negativeSide) const
49 {
50 // Calculate intersection with plane.
51 float t;
52 {
53 float denom = normal.dot(getDirection());
54
55 // Check intersect side
56 if (denom > + std::numeric_limits<float>::epsilon())
57 {
58 if (!negativeSide)
59 return std::pair<bool, float>(false, 0.0f);
60 }
61 else if (denom < - std::numeric_limits<float>::epsilon())
62 {
63 if (!positiveSide)
64 return std::pair<bool, float>(false, 0.0f);
65 }
66 else
67 {
68 // Parallel or triangle area is close to zero when
69 // the plane normal not normalized.
70 return std::pair<bool, float>(false, 0.0f);
71 }
72
73 t = normal.dot(a - getOrigin()) / denom;
74
75 if (t < 0)
76 {
77 // Intersection is behind origin
78 return std::pair<bool, float>(false, 0.0f);
79 }
80 }
81
82 // Calculate the largest area projection plane in X, Y or Z.
83 UINT32 i0, i1;
84 {
85 float n0 = Math::abs(normal[0]);
86 float n1 = Math::abs(normal[1]);
87 float n2 = Math::abs(normal[2]);
88
89 i0 = 1; i1 = 2;
90 if (n1 > n2)
91 {
92 if (n1 > n0) i0 = 0;
93 }
94 else
95 {
96 if (n2 > n0) i1 = 0;
97 }
98 }
99
100 // Check the intersection point is inside the triangle.
101 {
102 float u1 = b[i0] - a[i0];
103 float v1 = b[i1] - a[i1];
104 float u2 = c[i0] - a[i0];
105 float v2 = c[i1] - a[i1];
106 float u0 = t * getDirection()[i0] + getOrigin()[i0] - a[i0];
107 float v0 = t * getDirection()[i1] + getOrigin()[i1] - a[i1];
108
109 float alpha = u0 * v2 - u2 * v0;
110 float beta = u1 * v0 - u0 * v1;
111 float area = u1 * v2 - u2 * v1;
112
113 // Epsilon to avoid float precision errors.
114 const float EPSILON = 1e-6f;
115
116 float tolerance = - EPSILON * area;
117
118 if (area > 0)
119 {
120 if (alpha < tolerance || beta < tolerance || alpha+beta > area-tolerance)
121 return std::pair<bool, float>(false, 0.0f);
122 }
123 else
124 {
125 if (alpha > tolerance || beta > tolerance || alpha+beta < area-tolerance)
126 return std::pair<bool, float>(false, 0.0f);
127 }
128 }
129
130 return std::pair<bool, float>(true, t);
131 }
132}