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/BsConvexVolume.h" |
4 | #include "Math/BsAABox.h" |
5 | #include "Math/BsSphere.h" |
6 | #include "Math/BsPlane.h" |
7 | #include "Math/BsMath.h" |
8 | #include "Error/BsException.h" |
9 | |
10 | namespace bs |
11 | { |
12 | ConvexVolume::ConvexVolume(const Vector<Plane>& planes) |
13 | :mPlanes(planes) |
14 | { } |
15 | |
16 | ConvexVolume::ConvexVolume(const Matrix4& projectionMatrix, bool useNearPlane) |
17 | { |
18 | mPlanes.reserve(6); |
19 | |
20 | const Matrix4& proj = projectionMatrix; |
21 | |
22 | // Left |
23 | { |
24 | Plane plane; |
25 | plane.normal.x = proj[3][0] + proj[0][0]; |
26 | plane.normal.y = proj[3][1] + proj[0][1]; |
27 | plane.normal.z = proj[3][2] + proj[0][2]; |
28 | plane.d = proj[3][3] + proj[0][3]; |
29 | |
30 | mPlanes.push_back(plane); |
31 | } |
32 | |
33 | // Right |
34 | { |
35 | Plane plane; |
36 | plane.normal.x = proj[3][0] - proj[0][0]; |
37 | plane.normal.y = proj[3][1] - proj[0][1]; |
38 | plane.normal.z = proj[3][2] - proj[0][2]; |
39 | plane.d = proj[3][3] - proj[0][3]; |
40 | |
41 | mPlanes.push_back(plane); |
42 | } |
43 | |
44 | // Top |
45 | { |
46 | Plane plane; |
47 | plane.normal.x = proj[3][0] - proj[1][0]; |
48 | plane.normal.y = proj[3][1] - proj[1][1]; |
49 | plane.normal.z = proj[3][2] - proj[1][2]; |
50 | plane.d = proj[3][3] - proj[1][3]; |
51 | |
52 | mPlanes.push_back(plane); |
53 | } |
54 | |
55 | // Bottom |
56 | { |
57 | Plane plane; |
58 | plane.normal.x = proj[3][0] + proj[1][0]; |
59 | plane.normal.y = proj[3][1] + proj[1][1]; |
60 | plane.normal.z = proj[3][2] + proj[1][2]; |
61 | plane.d = proj[3][3] + proj[1][3]; |
62 | |
63 | mPlanes.push_back(plane); |
64 | } |
65 | |
66 | // Far |
67 | { |
68 | Plane plane; |
69 | plane.normal.x = proj[3][0] - proj[2][0]; |
70 | plane.normal.y = proj[3][1] - proj[2][1]; |
71 | plane.normal.z = proj[3][2] - proj[2][2]; |
72 | plane.d = proj[3][3] - proj[2][3]; |
73 | |
74 | mPlanes.push_back(plane); |
75 | } |
76 | |
77 | // Near |
78 | if(useNearPlane) |
79 | { |
80 | Plane plane; |
81 | plane.normal.x = proj[3][0] + proj[2][0]; |
82 | plane.normal.y = proj[3][1] + proj[2][1]; |
83 | plane.normal.z = proj[3][2] + proj[2][2]; |
84 | plane.d = proj[3][3] + proj[2][3]; |
85 | |
86 | mPlanes.push_back(plane); |
87 | } |
88 | |
89 | for (UINT32 i = 0; i < (UINT32)mPlanes.size(); i++) |
90 | { |
91 | float length = mPlanes[i].normal.normalize(); |
92 | mPlanes[i].d /= -length; |
93 | } |
94 | } |
95 | |
96 | bool ConvexVolume::intersects(const AABox& box) const |
97 | { |
98 | Vector3 center = box.getCenter(); |
99 | Vector3 extents = box.getHalfSize(); |
100 | Vector3 absExtents(Math::abs(extents.x), Math::abs(extents.y), Math::abs(extents.z)); |
101 | |
102 | for (auto& plane : mPlanes) |
103 | { |
104 | float dist = center.dot(plane.normal) - plane.d; |
105 | |
106 | float effectiveRadius = absExtents.x * Math::abs(plane.normal.x); |
107 | effectiveRadius += absExtents.y * Math::abs(plane.normal.y); |
108 | effectiveRadius += absExtents.z * Math::abs(plane.normal.z); |
109 | |
110 | if (dist < -effectiveRadius) |
111 | return false; |
112 | } |
113 | |
114 | return true; |
115 | } |
116 | |
117 | bool ConvexVolume::intersects(const Sphere& sphere) const |
118 | { |
119 | Vector3 center = sphere.getCenter(); |
120 | float radius = sphere.getRadius(); |
121 | |
122 | for (auto& plane : mPlanes) |
123 | { |
124 | float dist = center.dot(plane.normal) - plane.d; |
125 | |
126 | if (dist < -radius) |
127 | return false; |
128 | } |
129 | |
130 | return true; |
131 | } |
132 | |
133 | bool ConvexVolume::contains(const Vector3& p, float expand) const |
134 | { |
135 | for(auto& plane : mPlanes) |
136 | { |
137 | if (plane.getDistance(p) < -expand) |
138 | return false; |
139 | } |
140 | |
141 | return true; |
142 | } |
143 | |
144 | const Plane& ConvexVolume::getPlane(FrustumPlane whichPlane) const |
145 | { |
146 | if(whichPlane >= mPlanes.size()) |
147 | { |
148 | BS_EXCEPT(InvalidParametersException, "Requested plane does not exist in this volume."); |
149 | } |
150 | |
151 | return mPlanes[whichPlane]; |
152 | } |
153 | } |
154 |