Diligent Engine API Reference: D:/GitHub/DiligentEngine/DiligentCore/Common/interface/AdvancedMath.h Source File

Diligent Engine API Reference

AdvancedMath.h
1 /* Copyright 2015-2018 Egor Yusov
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
12 *
13 * In no event and under no legal theory, whether in tort (including negligence),
14 * contract, or otherwise, unless required by applicable law (such as deliberate
15 * and grossly negligent acts) or agreed to in writing, shall any Contributor be
16 * liable for any damages, including any direct, indirect, special, incidental,
17 * or consequential damages of any character arising as a result of this License or
18 * out of the use or inability to use the software (including but not limited to damages
19 * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
20 * all other commercial damages or losses), even if such Contributor has been advised
21 * of the possibility of such damages.
22 */
23
24 #pragma once
25
26 #include "BasicMath.h"
27
28 // Structure describing a plane
29 struct Plane3D
30 {
31 float3 Normal;
32 float Distance; //Distance from the coordinate system origin to the plane along the normal direction
33 };
34
35 struct ViewFrustum
36 {
37 Plane3D LeftPlane, RightPlane, BottomPlane, TopPlane, NearPlane, FarPlane;
38 };
39
40 struct ViewFrustumExt : public ViewFrustum
41 {
42 float3 FrustumCorners[8];
43 };
44
45 // For OpenGL, matrix is still considered row-major. The only difference is that
46 // near clip plane is at -1, not 0.
47 inline void ExtractViewFrustumPlanesFromMatrix(const float4x4 &Matrix, ViewFrustum &Frustum, bool bIsDirectX)
48 {
49 // For more details, see Gribb G., Hartmann K., "Fast Extraction of Viewing Frustum Planes from the
50 // World-View-Projection Matrix" (the paper is available at
51 // http://gamedevs.org/uploads/fast-extraction-viewing-frustum-planes-from-world-view-projection-matrix.pdf)
52
53 // Left clipping plane
54 Frustum.LeftPlane.Normal.x = Matrix._14 + Matrix._11;
55 Frustum.LeftPlane.Normal.y = Matrix._24 + Matrix._21;
56 Frustum.LeftPlane.Normal.z = Matrix._34 + Matrix._31;
57 Frustum.LeftPlane.Distance = Matrix._44 + Matrix._41;
58
59 // Right clipping plane
60 Frustum.RightPlane.Normal.x = Matrix._14 - Matrix._11;
61 Frustum.RightPlane.Normal.y = Matrix._24 - Matrix._21;
62 Frustum.RightPlane.Normal.z = Matrix._34 - Matrix._31;
63 Frustum.RightPlane.Distance = Matrix._44 - Matrix._41;
64
65 // Top clipping plane
66 Frustum.TopPlane.Normal.x = Matrix._14 - Matrix._12;
67 Frustum.TopPlane.Normal.y = Matrix._24 - Matrix._22;
68 Frustum.TopPlane.Normal.z = Matrix._34 - Matrix._32;
69 Frustum.TopPlane.Distance = Matrix._44 - Matrix._42;
70
71 // Bottom clipping plane
72 Frustum.BottomPlane.Normal.x = Matrix._14 + Matrix._12;
73 Frustum.BottomPlane.Normal.y = Matrix._24 + Matrix._22;
74 Frustum.BottomPlane.Normal.z = Matrix._34 + Matrix._32;
75 Frustum.BottomPlane.Distance = Matrix._44 + Matrix._42;
76
77 // Near clipping plane
78 if( bIsDirectX )
79 {
80 // 0 <= z <= w
81 Frustum.NearPlane.Normal.x = Matrix._13;
82 Frustum.NearPlane.Normal.y = Matrix._23;
83 Frustum.NearPlane.Normal.z = Matrix._33;
84 Frustum.NearPlane.Distance = Matrix._43;
85 }
86 else
87 {
88 // -w <= z <= w
89 Frustum.NearPlane.Normal.x = Matrix._14 + Matrix._13;
90 Frustum.NearPlane.Normal.y = Matrix._24 + Matrix._23;
91 Frustum.NearPlane.Normal.z = Matrix._34 + Matrix._33;
92 Frustum.NearPlane.Distance = Matrix._44 + Matrix._43;
93 }
94
95 // Far clipping plane
96 Frustum.FarPlane.Normal.x = Matrix._14 - Matrix._13;
97 Frustum.FarPlane.Normal.y = Matrix._24 - Matrix._23;
98 Frustum.FarPlane.Normal.z = Matrix._34 - Matrix._33;
99 Frustum.FarPlane.Distance = Matrix._44 - Matrix._43;
100 }
101
102 inline void ExtractViewFrustumPlanesFromMatrix(const float4x4 &Matrix, ViewFrustumExt &FrustumExt, bool bIsDirectX)
103 {
104 ExtractViewFrustumPlanesFromMatrix(Matrix, static_cast<ViewFrustum&>(FrustumExt), bIsDirectX);
105
106 // Compute frustum corners
107 float4x4 InvMatrix = inverseMatrix(Matrix);
108
109 float nearClipZ = bIsDirectX ? 0.f : -1.f;
110 static const float3 ProjSpaceCorners[] =
111 {
112 float3(-1,-1, nearClipZ),
113 float3( 1,-1, nearClipZ),
114 float3(-1, 1, nearClipZ),
115 float3( 1, 1, nearClipZ),
116
117 float3(-1,-1, 1),
118 float3( 1,-1, 1),
119 float3(-1, 1, 1),
120 float3( 1, 1, 1),
121 };
122
123 for(int i = 0; i < 8; ++i)
124 FrustumExt.FrustumCorners[i] = ProjSpaceCorners[i] * InvMatrix;
125 }
126
127 struct BoundBox
128 {
129 // Order must not be changed!
130 float fMinX, fMaxX, fMinY, fMaxY, fMinZ, fMaxZ;
131 };
132
133 enum class BoxVisibility
134 {
135 // Bounding box is guaranteed to be outside of the view frustum
136 // .
137 // . ' |
138 // . ' |
139 // | |
140 // . |
141 // ___ ' . |
142 // | | ' .
143 // |___|
144 //
145 Invisible,
146
147 // Bounding box intersects the frustum
148 // .
149 // . ' |
150 // . ' |
151 // | |
152 // _.__ |
153 // | '|. |
154 // |____| ' .
155 //
156 Intersecting,
157
158 // Bounding box is fully inside the view frustum
159 // .
160 // . ' |
161 // . '___ |
162 // | | | |
163 // . |___| |
164 // ' . |
165 // ' .
166 //
167 FullyVisible
168 };
169
170 template<bool TestFullVisibility>
171 inline BoxVisibility GetBoxVisibilityAgainstPlane(const Plane3D& Plane, const BoundBox &Box)
172 {
173 const float3& Normal = Plane.Normal;
174
175 float3 MaxPoint(
176 (Normal.x > 0) ? Box.fMaxX : Box.fMinX,
177 (Normal.y > 0) ? Box.fMaxY : Box.fMinY,
178 (Normal.z > 0) ? Box.fMaxZ : Box.fMinZ
179 );
180
181 float DMax = dot( MaxPoint, Normal ) + Plane.Distance;
182
183 if( DMax < 0 )
184 return BoxVisibility::Invisible;
185
186 if (TestFullVisibility)
187 {
188 float3 MinPoint(
189 (Normal.x > 0) ? Box.fMinX : Box.fMaxX,
190 (Normal.y > 0) ? Box.fMinY : Box.fMaxY,
191 (Normal.z > 0) ? Box.fMinZ : Box.fMaxZ
192 );
193
194 float DMin = dot(MinPoint, Normal) + Plane.Distance;
195
196 if (DMin > 0)
197 return BoxVisibility::FullyVisible;
198 }
199
200 return BoxVisibility::Intersecting;
201 }
202
203 // Tests if bounding box is visible by the camera
204 template<bool TestFullVisibility>
205 inline BoxVisibility GetBoxVisibility(const ViewFrustum &ViewFrustum, const BoundBox &Box)
206 {
207 const Plane3D *pPlanes = reinterpret_cast<const Plane3D*>(&ViewFrustum);
208
209 int NumPlanesInside = 0;
210 for(int iViewFrustumPlane = 0; iViewFrustumPlane < 6; iViewFrustumPlane++)
211 {
212 const Plane3D &CurrPlane = pPlanes[iViewFrustumPlane];
213 auto VisibilityAgainstPlane = GetBoxVisibilityAgainstPlane<TestFullVisibility>(CurrPlane, Box);
214
215 // If bounding box is "behind" one of the planes, it is definitely invisible
216 if (VisibilityAgainstPlane == BoxVisibility::Invisible)
217 return BoxVisibility::Invisible;
218
219 // Count total number of planes the bound box is inside
220 if (VisibilityAgainstPlane == BoxVisibility::FullyVisible)
221 ++NumPlanesInside;
222 }
223
224 return (TestFullVisibility && NumPlanesInside == 6) ? BoxVisibility::FullyVisible : BoxVisibility::Intersecting;
225 }
226
227 template<bool TestFullVisibility>
228 inline BoxVisibility GetBoxVisibility(const ViewFrustumExt &ViewFrustumExt, const BoundBox &Box)
229 {
230 auto Visibility = GetBoxVisibility<TestFullVisibility>(static_cast<const ViewFrustum&>(ViewFrustumExt), Box);
231 if (Visibility == BoxVisibility::FullyVisible || Visibility == BoxVisibility::Invisible)
232 return Visibility;
233
234 // Additionally test if the whole frustum is outside one of
235 // the the bounding box planes. This helps in the following situation:
236 //
237 //
238 // .
239 // / ' . .
240 // / AABB / . ' |
241 // / /. ' |
242 // ' . / | |
243 // * . | |
244 // ' . |
245 // ' . |
246 // ' .
247
248 for(int iBoundBoxPlane = 0; iBoundBoxPlane < 6; ++iBoundBoxPlane)
249 {
250 // struct BoundBox
251 // {
252 // float fMinX, fMaxX, fMinY, fMaxY, fMinZ, fMaxZ;
253 // };
254 float CurrPlaneCoord = reinterpret_cast<const float*>(&Box)[iBoundBoxPlane];
255 int iCoordOrder = iBoundBoxPlane / 2; // 0, 0, 1, 1, 2, 2
256 float fSign = (iBoundBoxPlane & 0x01) ? +1.f : -1.f;
257 bool bAllCornersOutside = true;
258 for(int iCorner=0; iCorner < 8; iCorner++)
259 {
260 float CurrCornerCoord = ViewFrustumExt.FrustumCorners[iCorner][iCoordOrder];
261 if( fSign * (CurrPlaneCoord - CurrCornerCoord) > 0)
262 {
263 bAllCornersOutside = false;
264 break;
265 }
266 }
267 if( bAllCornersOutside )
268 return BoxVisibility::Invisible;
269 }
270
271 return BoxVisibility::Intersecting;
272 }
273
274 inline float GetPointToBoxDistance(const BoundBox &BndBox, const float3 &Pos)
275 {
276 VERIFY_EXPR(BndBox.fMaxX >= BndBox.fMinX &&
277 BndBox.fMaxY >= BndBox.fMinY &&
278 BndBox.fMaxZ >= BndBox.fMinZ);
279 float fdX = (Pos.x > BndBox.fMaxX) ? (Pos.x - BndBox.fMaxX) : ( (Pos.x < BndBox.fMinX) ? (BndBox.fMinX - Pos.x) : 0.f );
280 float fdY = (Pos.y > BndBox.fMaxY) ? (Pos.y - BndBox.fMaxY) : ( (Pos.y < BndBox.fMinY) ? (BndBox.fMinY - Pos.y) : 0.f );
281 float fdZ = (Pos.z > BndBox.fMaxZ) ? (Pos.z - BndBox.fMaxZ) : ( (Pos.z < BndBox.fMinZ) ? (BndBox.fMinZ - Pos.z) : 0.f );
282 VERIFY_EXPR(fdX >= 0 && fdY >= 0 && fdZ >= 0);
283
284 float3 RangeVec(fdX, fdY, fdZ);
285 return length( RangeVec );
286 }
287
288 inline bool operator == (const Plane3D &p1, const Plane3D &p2)
289 {
290 return p1.Normal == p2.Normal &&
291 p1.Distance == p2.Distance;
292 }
293
294 inline bool operator == (const ViewFrustum &f1, const ViewFrustum &f2)
295 {
296 return f1.LeftPlane == f2.LeftPlane &&
297 f1.RightPlane == f2.RightPlane &&
298 f1.BottomPlane == f2.BottomPlane &&
299 f1.TopPlane == f2.TopPlane &&
300 f1.NearPlane == f2.NearPlane &&
301 f1.FarPlane == f2.FarPlane;
302 }
303
304 inline bool operator == (const ViewFrustumExt &f1, const ViewFrustumExt &f2)
305 {
306 if (! (static_cast<const ViewFrustum &>(f1) == static_cast<const ViewFrustum &>(f2)) )
307 return false;
308
309 for (int c = 0; c < _countof(f1.FrustumCorners); ++c)
310 if (f1.FrustumCorners[c] != f2.FrustumCorners[c])
311 return false;
312
313 return true;
314 }
315
316 namespace std
317 {
318 template<>
319 struct hash<Plane3D>
320 {
321 size_t operator()( const Plane3D &Plane ) const
322 {
323 return Diligent::ComputeHash(Plane.Normal, Plane.Distance);
324 }
325 };
326
327 template<>
328 struct hash<ViewFrustum>
329 {
330 size_t operator()( const ViewFrustum &Frustum ) const
331 {
332 return Diligent::ComputeHash(Frustum.LeftPlane, Frustum.RightPlane, Frustum.BottomPlane, Frustum.TopPlane, Frustum.NearPlane, Frustum.FarPlane);
333 }
334 };
335
336 template<>
337 struct hash<ViewFrustumExt>
338 {
339 size_t operator()( const ViewFrustumExt &Frustum ) const
340 {
341 auto Seed = Diligent::ComputeHash(static_cast<const ViewFrustum&>(Frustum));
342 for (int Corner = 0; Corner < _countof(Frustum.FrustumCorners); ++Corner)
343 Diligent::HashCombine(Seed, Frustum.FrustumCorners[Corner]);
344 return Seed;
345 }
346 };
347 }
std
Definition: AdvancedMath.h:316