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
10namespace 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