Diligent Engine  v.2.4.g
AdvancedMath.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2019-2021 Diligent Graphics LLC
3  * Copyright 2015-2019 Egor Yusov
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * In no event and under no legal theory, whether in tort (including negligence),
18  * contract, or otherwise, unless required by applicable law (such as deliberate
19  * and grossly negligent acts) or agreed to in writing, shall any Contributor be
20  * liable for any damages, including any direct, indirect, special, incidental,
21  * or consequential damages of any character arising as a result of this License or
22  * out of the use or inability to use the software (including but not limited to damages
23  * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
24  * all other commercial damages or losses), even if such Contributor has been advised
25  * of the possibility of such damages.
26  */
27 
28 #pragma once
29 
30 #include <float.h>
31 
32 #include "../../Platforms/interface/PlatformDefinitions.h"
33 #include "../../Primitives/interface/FlagEnum.h"
34 
35 #include "BasicMath.hpp"
36 
37 namespace Diligent
38 {
39 
40 // Structure describing a plane
41 struct Plane3D
42 {
44  float Distance = 0; //Distance from the coordinate system origin to the plane along the normal direction
45 
46  operator float4&()
47  {
48  return *reinterpret_cast<float4*>(this);
49  }
50  operator const float4&() const
51  {
52  return *reinterpret_cast<const float4*>(this);
53  }
54 };
55 
57 {
59  {
67  };
68 
75 
76  const Plane3D& GetPlane(PLANE_IDX Idx) const
77  {
78  VERIFY_EXPR(Idx < NUM_PLANES);
79  const Plane3D* Planes = reinterpret_cast<const Plane3D*>(this);
80  return Planes[static_cast<size_t>(Idx)];
81  }
82 
84  {
85  VERIFY_EXPR(Idx < NUM_PLANES);
86  Plane3D* Planes = reinterpret_cast<Plane3D*>(this);
87  return Planes[static_cast<size_t>(Idx)];
88  }
89 };
90 
91 struct ViewFrustumExt : public ViewFrustum
92 {
94 };
95 
96 // For OpenGL, matrix is still considered row-major. The only difference is that
97 // near clip plane is at -1, not 0.
98 //
99 // Note that returned plane normal vectors are not normalized, which does not make a difference
100 // when testing a point against the plane:
101 //
102 // IsPointInsidePlane = dot(Plane.Normal, Point) < Plane.Distance
103 //
104 // However, to use the planes with other distances (e.g. for testing a sphere against the plane),
105 // the normal vectors must be normalized and the distances scaled accordingly.
106 inline void ExtractViewFrustumPlanesFromMatrix(const float4x4& Matrix, ViewFrustum& Frustum, bool bIsOpenGL)
107 {
108  // For more details, see Gribb G., Hartmann K., "Fast Extraction of Viewing Frustum Planes from the
109  // World-View-Projection Matrix" (the paper is available at
110  // http://gamedevs.org/uploads/fast-extraction-viewing-frustum-planes-from-world-view-projection-matrix.pdf)
111 
112  // Left clipping plane
113  Frustum.LeftPlane.Normal.x = Matrix._14 + Matrix._11;
114  Frustum.LeftPlane.Normal.y = Matrix._24 + Matrix._21;
115  Frustum.LeftPlane.Normal.z = Matrix._34 + Matrix._31;
116  Frustum.LeftPlane.Distance = Matrix._44 + Matrix._41;
117 
118  // Right clipping plane
119  Frustum.RightPlane.Normal.x = Matrix._14 - Matrix._11;
120  Frustum.RightPlane.Normal.y = Matrix._24 - Matrix._21;
121  Frustum.RightPlane.Normal.z = Matrix._34 - Matrix._31;
122  Frustum.RightPlane.Distance = Matrix._44 - Matrix._41;
123 
124  // Top clipping plane
125  Frustum.TopPlane.Normal.x = Matrix._14 - Matrix._12;
126  Frustum.TopPlane.Normal.y = Matrix._24 - Matrix._22;
127  Frustum.TopPlane.Normal.z = Matrix._34 - Matrix._32;
128  Frustum.TopPlane.Distance = Matrix._44 - Matrix._42;
129 
130  // Bottom clipping plane
131  Frustum.BottomPlane.Normal.x = Matrix._14 + Matrix._12;
132  Frustum.BottomPlane.Normal.y = Matrix._24 + Matrix._22;
133  Frustum.BottomPlane.Normal.z = Matrix._34 + Matrix._32;
134  Frustum.BottomPlane.Distance = Matrix._44 + Matrix._42;
135 
136  // Near clipping plane
137  if (bIsOpenGL)
138  {
139  // -w <= z <= w
140  Frustum.NearPlane.Normal.x = Matrix._14 + Matrix._13;
141  Frustum.NearPlane.Normal.y = Matrix._24 + Matrix._23;
142  Frustum.NearPlane.Normal.z = Matrix._34 + Matrix._33;
143  Frustum.NearPlane.Distance = Matrix._44 + Matrix._43;
144  }
145  else
146  {
147  // 0 <= z <= w
148  Frustum.NearPlane.Normal.x = Matrix._13;
149  Frustum.NearPlane.Normal.y = Matrix._23;
150  Frustum.NearPlane.Normal.z = Matrix._33;
151  Frustum.NearPlane.Distance = Matrix._43;
152  }
153 
154  // Far clipping plane
155  Frustum.FarPlane.Normal.x = Matrix._14 - Matrix._13;
156  Frustum.FarPlane.Normal.y = Matrix._24 - Matrix._23;
157  Frustum.FarPlane.Normal.z = Matrix._34 - Matrix._33;
158  Frustum.FarPlane.Distance = Matrix._44 - Matrix._43;
159 }
160 
161 inline void ExtractViewFrustumPlanesFromMatrix(const float4x4& Matrix, ViewFrustumExt& FrustumExt, bool bIsOpenGL)
162 {
163  ExtractViewFrustumPlanesFromMatrix(Matrix, static_cast<ViewFrustum&>(FrustumExt), bIsOpenGL);
164 
165  // Compute frustum corners
166  float4x4 InvMatrix = Matrix.Inverse();
167 
168  float nearClipZ = bIsOpenGL ? -1.f : 0.f;
169 
170  static const float3 ProjSpaceCorners[] =
171  {
172  // clang-format off
173  float3(-1, -1, nearClipZ),
174  float3( 1, -1, nearClipZ),
175  float3(-1, 1, nearClipZ),
176  float3( 1, 1, nearClipZ),
177 
178  float3(-1, -1, 1),
179  float3( 1, -1, 1),
180  float3(-1, 1, 1),
181  float3( 1, 1, 1),
182  // clang-format on
183  };
184 
185  for (int i = 0; i < 8; ++i)
186  FrustumExt.FrustumCorners[i] = ProjSpaceCorners[i] * InvMatrix;
187 }
188 
189 struct BoundBox
190 {
193 
194  // Computes new bounding box by applying transform matrix m to the box
195  BoundBox Transform(const float4x4& m) const
196  {
197  BoundBox NewBB;
198  NewBB.Min = float3::MakeVector(m[3]);
199  NewBB.Max = NewBB.Min;
200  float3 v0, v1;
201 
202  float3 right = float3::MakeVector(m[0]);
203 
204  v0 = right * Min.x;
205  v1 = right * Max.x;
206  NewBB.Min += std::min(v0, v1);
207  NewBB.Max += std::max(v0, v1);
208 
209  float3 up = float3::MakeVector(m[1]);
210 
211  v0 = up * Min.y;
212  v1 = up * Max.y;
213  NewBB.Min += std::min(v0, v1);
214  NewBB.Max += std::max(v0, v1);
215 
216  float3 back = float3::MakeVector(m[2]);
217 
218  v0 = back * Min.z;
219  v1 = back * Max.z;
220  NewBB.Min += std::min(v0, v1);
221  NewBB.Max += std::max(v0, v1);
222 
223  return NewBB;
224  }
225 };
226 
227 enum class BoxVisibility
228 {
229  // Bounding box is guaranteed to be outside of the view frustum
230  // .
231  // . ' |
232  // . ' |
233  // | |
234  // . |
235  // ___ ' . |
236  // | | ' .
237  // |___|
238  //
239  Invisible,
240 
241  // Bounding box intersects the frustum
242  // .
243  // . ' |
244  // . ' |
245  // | |
246  // _.__ |
247  // | '|. |
248  // |____| ' .
249  //
250  Intersecting,
251 
252  // Bounding box is fully inside the view frustum
253  // .
254  // . ' |
255  // . '___ |
256  // | | | |
257  // . |___| |
258  // ' . |
259  // ' .
260  //
262 };
263 
265 inline float3 GetBoxNearestCorner(const float3& Direction, const BoundBox& Box)
266 {
267  return float3 //
268  {
269  (Direction.x > 0) ? Box.Min.x : Box.Max.x,
270  (Direction.y > 0) ? Box.Min.y : Box.Max.y,
271  (Direction.z > 0) ? Box.Min.z : Box.Max.z //
272  };
273 }
274 
276 inline float3 GetBoxFarthestCorner(const float3& Direction, const BoundBox& Box)
277 {
278  return float3 //
279  {
280  (Direction.x > 0) ? Box.Max.x : Box.Min.x,
281  (Direction.y > 0) ? Box.Max.y : Box.Min.y,
282  (Direction.z > 0) ? Box.Max.z : Box.Min.z //
283  };
284 }
285 
287 {
288  const float3& Normal = Plane.Normal;
289 
290  float3 MaxPoint //
291  {
292  (Normal.x > 0) ? Box.Max.x : Box.Min.x,
293  (Normal.y > 0) ? Box.Max.y : Box.Min.y,
294  (Normal.z > 0) ? Box.Max.z : Box.Min.z //
295  };
296  float DMax = dot(MaxPoint, Normal) + Plane.Distance;
297  if (DMax < 0)
299 
300  float3 MinPoint //
301  {
302  (Normal.x > 0) ? Box.Min.x : Box.Max.x,
303  (Normal.y > 0) ? Box.Min.y : Box.Max.y,
304  (Normal.z > 0) ? Box.Min.z : Box.Max.z //
305  };
306  float DMin = dot(MinPoint, Normal) + Plane.Distance;
307  if (DMin > 0)
309 
311 }
312 
313 // Flags must be listed in the same order as planes in the ViewFrustum struct:
314 // LeftPlane, RightPlane, BottomPlane, TopPlane, NearPlane, FarPlane
316 {
324 
331 
337 };
339 
340 // Tests if bounding box is visible by the camera
342  const BoundBox& Box,
344 {
345  int NumPlanesInside = 0;
346  int TotalPlanes = 0;
347  for (Uint32 plane_idx = 0; plane_idx < ViewFrustum::NUM_PLANES; ++plane_idx)
348  {
349  if ((PlaneFlags & (1 << plane_idx)) == 0)
350  continue;
351 
352  const Plane3D& CurrPlane = ViewFrustum.GetPlane(static_cast<ViewFrustum::PLANE_IDX>(plane_idx));
353 
354  auto VisibilityAgainstPlane = GetBoxVisibilityAgainstPlane(CurrPlane, Box);
355 
356  // If bounding box is "behind" one of the planes, it is definitely invisible
357  if (VisibilityAgainstPlane == BoxVisibility::Invisible)
359 
360  // Count total number of planes the bound box is inside
361  if (VisibilityAgainstPlane == BoxVisibility::FullyVisible)
362  ++NumPlanesInside;
363 
364  ++TotalPlanes;
365  }
366 
367  return (NumPlanesInside == TotalPlanes) ? BoxVisibility::FullyVisible : BoxVisibility::Intersecting;
368 }
369 
371  const BoundBox& Box,
373 {
374  auto Visibility = GetBoxVisibility(static_cast<const ViewFrustum&>(ViewFrustumExt), Box, PlaneFlags);
375  if (Visibility == BoxVisibility::FullyVisible || Visibility == BoxVisibility::Invisible)
376  return Visibility;
377 
379  {
380  // Additionally test if the whole frustum is outside one of
381  // the the bounding box planes. This helps in the following situation:
382  //
383  //
384  // .
385  // / ' . .
386  // / AABB / . ' |
387  // / /. ' |
388  // ' . / | |
389  // * . | |
390  // ' . |
391  // ' . |
392  // ' .
393 
394  // Test all frustum corners against every bound box plane
395  for (int iBoundBoxPlane = 0; iBoundBoxPlane < 6; ++iBoundBoxPlane)
396  {
397  // struct BoundBox
398  // {
399  // float3 Min;
400  // float3 Max;
401  // };
402  float CurrPlaneCoord = reinterpret_cast<const float*>(&Box)[iBoundBoxPlane];
403  // Bound box normal is one of the axis, so we just need to pick the right coordinate
404  int iCoordOrder = iBoundBoxPlane % 3; // 0, 1, 2, 0, 1, 2
405  // Since plane normal is directed along one of the axis, we only need to select
406  // if it is pointing in the positive (max planes) or negative (min planes) direction
407  float fSign = (iBoundBoxPlane >= 3) ? +1.f : -1.f;
408  bool bAllCornersOutside = true;
409  for (int iCorner = 0; iCorner < 8; iCorner++)
410  {
411  // Pick the frustum corner coordinate
412  float CurrCornerCoord = ViewFrustumExt.FrustumCorners[iCorner][iCoordOrder];
413  // Dot product is simply the coordinate difference multiplied by the sign
414  if (fSign * (CurrPlaneCoord - CurrCornerCoord) > 0)
415  {
416  bAllCornersOutside = false;
417  break;
418  }
419  }
420  if (bAllCornersOutside)
422  }
423  }
424 
426 }
427 
428 inline float GetPointToBoxDistance(const BoundBox& BndBox, const float3& Pos)
429 {
430  VERIFY_EXPR(BndBox.Max.x >= BndBox.Min.x &&
431  BndBox.Max.y >= BndBox.Min.y &&
432  BndBox.Max.z >= BndBox.Min.z);
433  float fdX = (Pos.x > BndBox.Max.x) ? (Pos.x - BndBox.Max.x) : ((Pos.x < BndBox.Min.x) ? (BndBox.Min.x - Pos.x) : 0.f);
434  float fdY = (Pos.y > BndBox.Max.y) ? (Pos.y - BndBox.Max.y) : ((Pos.y < BndBox.Min.y) ? (BndBox.Min.y - Pos.y) : 0.f);
435  float fdZ = (Pos.z > BndBox.Max.z) ? (Pos.z - BndBox.Max.z) : ((Pos.z < BndBox.Min.z) ? (BndBox.Min.z - Pos.z) : 0.f);
436  VERIFY_EXPR(fdX >= 0 && fdY >= 0 && fdZ >= 0);
437 
438  float3 RangeVec(fdX, fdY, fdZ);
439  return length(RangeVec);
440 }
441 
442 inline bool operator==(const Plane3D& p1, const Plane3D& p2)
443 {
444  return p1.Normal == p2.Normal &&
445  p1.Distance == p2.Distance;
446 }
447 
448 inline bool operator==(const ViewFrustum& f1, const ViewFrustum& f2)
449 {
450  // clang-format off
451  return f1.LeftPlane == f2.LeftPlane &&
452  f1.RightPlane == f2.RightPlane &&
453  f1.BottomPlane == f2.BottomPlane &&
454  f1.TopPlane == f2.TopPlane &&
455  f1.NearPlane == f2.NearPlane &&
456  f1.FarPlane == f2.FarPlane;
457  // clang-format on
458 }
459 
460 inline bool operator==(const ViewFrustumExt& f1, const ViewFrustumExt& f2)
461 {
462  if (!(static_cast<const ViewFrustum&>(f1) == static_cast<const ViewFrustum&>(f2)))
463  return false;
464 
465  for (int c = 0; c < _countof(f1.FrustumCorners); ++c)
466  if (f1.FrustumCorners[c] != f2.FrustumCorners[c])
467  return false;
468 
469  return true;
470 }
471 
472 template <typename T, typename Y>
473 T HermiteSpline(T f0, // F(0)
474  T f1, // F(1)
475  T t0, // F'(0)
476  T t1, // F'(1)
477  Y x)
478 {
479  // https://en.wikipedia.org/wiki/Cubic_Hermite_spline
480  auto x2 = x * x;
481  auto x3 = x2 * x;
482  return (2 * x3 - 3 * x2 + 1) * f0 + (x3 - 2 * x2 + x) * t0 + (-2 * x3 + 3 * x2) * f1 + (x3 - x2) * t1;
483 }
484 
485 // Retuns the minimum bounding sphere of a view frustum
486 inline void GetFrustumMinimumBoundingSphere(float Proj_00, // cot(HorzFOV / 2)
487  float Proj_11, // cot(VertFOV / 2) == proj_00 / AspectRatio
488  float NearPlane, // Near clip plane
489  float FarPlane, // Far clip plane
490  float3& Center, // Sphere center == (0, 0, c)
491  float& Radius // Sphere radius
492 )
493 {
494  // https://lxjk.github.io/2017/04/15/Calculate-Minimal-Bounding-Sphere-of-Frustum.html
495  VERIFY_EXPR(FarPlane >= NearPlane);
496  auto k2 = 1.f / (Proj_00 * Proj_00) + 1.f / (Proj_11 * Proj_11);
497  if (k2 > (FarPlane - NearPlane) / (FarPlane + NearPlane))
498  {
499  Center = float3(0, 0, FarPlane);
500  Radius = FarPlane * std::sqrt(k2);
501  }
502  else
503  {
504  Center = float3(0, 0, 0.5f * (FarPlane + NearPlane) * (1 + k2));
505  Radius = 0.5f * std::sqrt((FarPlane - NearPlane) * (FarPlane - NearPlane) + 2 * (FarPlane * FarPlane + NearPlane * NearPlane) * k2 + (FarPlane + NearPlane) * (FarPlane + NearPlane) * k2 * k2);
506  }
507 }
508 
510 inline bool IntersectRayBox3D(const float3& RayOrigin,
511  const float3& RayDirection,
512  float3 BoxMin,
513  float3 BoxMax,
514  float& EnterDist,
515  float& ExitDist)
516 {
517  VERIFY_EXPR(RayDirection != float3(0, 0, 0));
518 
519  BoxMin -= RayOrigin;
520  BoxMax -= RayOrigin;
521 
522  static constexpr float Epsilon = 1e-20f;
523 
524  float3 AbsRayDir = abs(RayDirection);
525  float3 t_min //
526  {
527  AbsRayDir.x > Epsilon ? BoxMin.x / RayDirection.x : +FLT_MAX,
528  AbsRayDir.y > Epsilon ? BoxMin.y / RayDirection.y : +FLT_MAX,
529  AbsRayDir.z > Epsilon ? BoxMin.z / RayDirection.z : +FLT_MAX //
530  };
531  float3 t_max //
532  {
533  AbsRayDir.x > Epsilon ? BoxMax.x / RayDirection.x : -FLT_MAX,
534  AbsRayDir.y > Epsilon ? BoxMax.y / RayDirection.y : -FLT_MAX,
535  AbsRayDir.z > Epsilon ? BoxMax.z / RayDirection.z : -FLT_MAX //
536  };
537 
538  EnterDist = max3(std::min(t_min.x, t_max.x), std::min(t_min.y, t_max.y), std::min(t_min.z, t_max.z));
539  ExitDist = min3(std::max(t_min.x, t_max.x), std::max(t_min.y, t_max.y), std::max(t_min.z, t_max.z));
540 
541  // if ExitDist < 0, the ray intersects AABB, but the whole AABB is behind it
542  // if EnterDist > ExitDist, the ray doesn't intersect AABB
543  return ExitDist >= 0 && EnterDist <= ExitDist;
544 }
545 
547 inline bool IntersectRayAABB(const float3& RayOrigin,
548  const float3& RayDirection,
549  const BoundBox& AABB,
550  float& EnterDist,
551  float& ExitDist)
552 {
553  return IntersectRayBox3D(RayOrigin, RayDirection, AABB.Min, AABB.Max, EnterDist, ExitDist);
554 }
555 
557 inline bool IntersectRayBox2D(const float2& RayOrigin,
558  const float2& RayDirection,
559  float2 BoxMin,
560  float2 BoxMax,
561  float& EnterDist,
562  float& ExitDist)
563 {
564  VERIFY_EXPR(RayDirection != float2(0, 0));
565 
566  BoxMin -= RayOrigin;
567  BoxMax -= RayOrigin;
568 
569  static constexpr float Epsilon = 1e-20f;
570 
571  float2 AbsRayDir = abs(RayDirection);
572  float2 t_min //
573  {
574  AbsRayDir.x > Epsilon ? BoxMin.x / RayDirection.x : +FLT_MAX,
575  AbsRayDir.y > Epsilon ? BoxMin.y / RayDirection.y : +FLT_MAX //
576  };
577  float2 t_max //
578  {
579  AbsRayDir.x > Epsilon ? BoxMax.x / RayDirection.x : -FLT_MAX,
580  AbsRayDir.y > Epsilon ? BoxMax.y / RayDirection.y : -FLT_MAX //
581  };
582 
583  EnterDist = std::max(std::min(t_min.x, t_max.x), std::min(t_min.y, t_max.y));
584  ExitDist = std::min(std::max(t_min.x, t_max.x), std::max(t_min.y, t_max.y));
585 
586  // if ExitDist < 0, the ray intersects AABB, but the whole AABB is behind it
587  // if EnterDist > ExitDist, the ray doesn't intersect AABB
588  return ExitDist >= 0 && EnterDist <= ExitDist;
589 }
590 
591 
596 inline float IntersectRayTriangle(const float3& V0,
597  const float3& V1,
598  const float3& V2,
599  const float3& RayOrigin,
600  const float3& RayDirection,
601  bool CullBackFace = false)
602 {
603  float3 V0_V1 = V1 - V0;
604  float3 V0_V2 = V2 - V0;
605 
606  float3 PVec = cross(RayDirection, V0_V2);
607 
608  float Det = dot(V0_V1, PVec);
609 
610  float t = +FLT_MAX;
611 
612  static constexpr float Epsilon = 1e-10f;
613  // If determinant is near zero, the ray lies in the triangle plane
614  if (Det > Epsilon || (!CullBackFace && Det < -Epsilon))
615  {
616  float3 V0_RO = RayOrigin - V0;
617 
618  // calculate U parameter and test bounds
619  float u = dot(V0_RO, PVec) / Det;
620  if (u >= 0 && u <= 1)
621  {
622  float3 QVec = cross(V0_RO, V0_V1);
623 
624  // calculate V parameter and test bounds
625  float v = dot(RayDirection, QVec) / Det;
626  if (v >= 0 && u + v <= 1)
627  {
628  // calculate t, ray intersects triangle
629  t = dot(V0_V2, QVec) / Det;
630  }
631  }
632  }
633 
634  return t;
635 }
636 
637 
639 
668 template <typename TCallback>
670  float2 f2End,
671  int2 i2GridSize,
672  TCallback Callback)
673 {
674  VERIFY_EXPR(i2GridSize.x > 0 && i2GridSize.y > 0);
675  const auto f2GridSize = i2GridSize.Recast<float>();
676 
677  if (f2Start == f2End)
678  {
679  if (f2Start.x >= 0 && f2Start.x < f2GridSize.x &&
680  f2Start.y >= 0 && f2Start.y < f2GridSize.y)
681  {
682  Callback(f2Start.Recast<int>());
683  }
684  return;
685  }
686 
687  float2 f2Direction = f2End - f2Start;
688 
689  float EnterDist, ExitDist;
690  if (IntersectRayBox2D(f2Start, f2Direction, float2{0, 0}, f2GridSize, EnterDist, ExitDist))
691  {
692  f2End = f2Start + f2Direction * std::min(ExitDist, 1.f);
693  f2Start = f2Start + f2Direction * std::max(EnterDist, 0.f);
694  // Clamp start and end points to avoid FP precision issues
695  f2Start = clamp(f2Start, float2{0, 0}, f2GridSize);
696  f2End = clamp(f2End, float2{0, 0}, f2GridSize);
697 
698  const int dh = f2Direction.x > 0 ? 1 : -1;
699  const int dv = f2Direction.y > 0 ? 1 : -1;
700  const float p = f2Direction.y * f2Start.x - f2Direction.x * f2Start.y;
701  const float tx = p - f2Direction.y * static_cast<float>(dh);
702  const float ty = p + f2Direction.x * static_cast<float>(dv);
703 
704  const int2 i2End = f2End.Recast<int>();
705  VERIFY_EXPR(i2End.x >= 0 && i2End.y >= 0 && i2End.x <= i2GridSize.x && i2End.y <= i2GridSize.y);
706 
707  int2 i2Pos = f2Start.Recast<int>();
708  VERIFY_EXPR(i2Pos.x >= 0 && i2Pos.y >= 0 && i2Pos.x <= i2GridSize.x && i2Pos.y <= i2GridSize.y);
709 
710  // Loop condition checks if we missed the end point of the line due to
711  // floating point precision issues.
712  // Normally we exit the loop when i2Pos == i2End.
713  while ((i2End.x - i2Pos.x) * dh >= 0 &&
714  (i2End.y - i2Pos.y) * dv >= 0)
715  {
716  if (i2Pos.x < i2GridSize.x && i2Pos.y < i2GridSize.y)
717  {
718  if (!Callback(i2Pos))
719  break;
720  }
721 
722  if (i2Pos == i2End)
723  {
724  // End of the line
725  break;
726  }
727  else
728  {
729  // step to the next cell
730  float t = f2Direction.x * (static_cast<float>(i2Pos.y) + 0.5f) - f2Direction.y * (static_cast<float>(i2Pos.x) + 0.5f);
731  if (std::abs(t + tx) < std::abs(t + ty))
732  i2Pos.x += dh;
733  else
734  i2Pos.y += dv;
735  }
736  }
737  }
738 }
739 
740 
742 
753 template <typename T, typename IntermediateType>
755  const Vector2<T>& V1,
756  const Vector2<T>& V2,
757  const Vector2<T>& Point,
758  bool AllowEdges)
759 {
760  using DirType = Vector2<IntermediateType>;
761 
762  const DirType Rib[3] = //
763  {
764  DirType //
765  {
766  IntermediateType{V1.x} - IntermediateType{V0.x},
767  IntermediateType{V1.y} - IntermediateType{V0.y},
768  },
769  DirType //
770  {
771  IntermediateType{V2.x} - IntermediateType{V1.x},
772  IntermediateType{V2.y} - IntermediateType{V1.y},
773  },
774  DirType //
775  {
776  IntermediateType{V0.x} - IntermediateType{V2.x},
777  IntermediateType{V0.y} - IntermediateType{V2.y},
778  } //
779  };
780 
781  const DirType VertToPoint[3] = //
782  {
783  DirType //
784  {
785  IntermediateType{Point.x} - IntermediateType{V0.x},
786  IntermediateType{Point.y} - IntermediateType{V0.y} //
787  },
788  DirType //
789  {
790  IntermediateType{Point.x} - IntermediateType{V1.x},
791  IntermediateType{Point.y} - IntermediateType{V1.y} //
792  },
793  DirType //
794  {
795  IntermediateType{Point.x} - IntermediateType{V2.x},
796  IntermediateType{Point.y} - IntermediateType{V2.y} //
797  } //
798  };
799 
800  IntermediateType NormalZ[3];
801  for (int i = 0; i < 3; i++)
802  {
803  NormalZ[i] = Rib[i].x * VertToPoint[i].y - Rib[i].y * VertToPoint[i].x;
804  }
805 
806  // clang-format off
807  if (AllowEdges)
808  {
809  return (NormalZ[0] >= 0 && NormalZ[1] >= 0 && NormalZ[2] >= 0) ||
810  (NormalZ[0] <= 0 && NormalZ[1] <= 0 && NormalZ[2] <= 0);
811  }
812  else
813  {
814  return (NormalZ[0] > 0 && NormalZ[1] > 0 && NormalZ[2] > 0) ||
815  (NormalZ[0] < 0 && NormalZ[1] < 0 && NormalZ[2] < 0);
816  }
817  // clang-format on
818 }
819 
820 template <typename T>
822  const Vector2<T>& V1,
823  const Vector2<T>& V2,
824  const Vector2<T>& Point,
825  bool AllowEdges)
826 {
827  return IsPointInsideTriangle<T, T>(V0, V1, V2, Point, AllowEdges);
828 }
829 
830 
832 
856 template <typename T,
857  class TCallback>
859  Vector2<T> V1,
860  Vector2<T> V2,
861  TCallback Callback)
862 {
863  if (V1.y < V0.y)
864  std::swap(V1, V0);
865  if (V2.y < V0.y)
866  std::swap(V2, V0);
867  if (V2.y < V1.y)
868  std::swap(V2, V1);
869 
870  VERIFY_EXPR(V0.y <= V1.y && V1.y <= V2.y);
871 
872  const int iStartRow = static_cast<int>(FastCeil(V0.y));
873  const int iEndRow = static_cast<int>(FastFloor(V2.y));
874 
875  if (iStartRow == iEndRow)
876  {
877  auto iStartCol = static_cast<int>(FastCeil(min3(V0.x, V1.x, V2.x)));
878  auto iEndCol = static_cast<int>(FastFloor(max3(V0.x, V1.x, V2.x)));
879  for (int iCol = iStartCol; iCol <= iEndCol; ++iCol)
880  {
881  Callback(int2{iCol, iStartRow});
882  }
883  return;
884  }
885 
886  auto LerpCol = [](T StartCol, T EndCol, T StartRow, T EndRow, int CurrRow) //
887  {
888  return StartCol +
889  ((EndCol - StartCol) * (static_cast<T>(CurrRow) - StartRow)) / (EndRow - StartRow);
890  };
891 
892  for (int iRow = iStartRow; iRow <= iEndRow; ++iRow)
893  {
894  auto dStartCol = LerpCol(V0.x, V2.x, V0.y, V2.y, iRow);
895 
896  T dEndCol;
897  if (static_cast<T>(iRow) < V1.y)
898  {
899  // V2.
900  // V2-------V1 \' .
901  // | .' <- \ ' . V1
902  // | .' <- \ / <-
903  // | .' <- \ / <-
904  // .' <- \/ <-
905  // V0 <- V0 <-
906  dEndCol = LerpCol(V0.x, V1.x, V0.y, V1.y, iRow);
907  }
908  else
909  {
910  if (V1.y < V2.y)
911  {
912  // V2. <-
913  // V2 <- \' . <-
914  // |'. <- \ ' . V1 <-
915  // | '. <- \ /
916  // | '. <- \ /
917  // | '. <- \/
918  // V0-------V1 <- V0
919  dEndCol = LerpCol(V1.x, V2.x, V1.y, V2.y, iRow);
920  }
921  else
922  {
923  // V2-------V1 <-
924  // | .'
925  // | .'
926  // | .'
927  // .'
928  // V0
929  dEndCol = V1.x;
930  }
931  }
932  if (dStartCol > dEndCol)
933  std::swap(dStartCol, dEndCol);
934 
935  int iStartCol = static_cast<int>(FastCeil(dStartCol));
936  int iEndCol = static_cast<int>(FastFloor(dEndCol));
937 
938  for (int iCol = iStartCol; iCol <= iEndCol; ++iCol)
939  {
940  Callback(int2{iCol, iRow});
941  }
942  }
943 }
944 
945 
947 
958 template <bool AllowTouch, typename T>
959 bool CheckBox2DBox2DOverlap(const Vector2<T>& Box0Min,
960  const Vector2<T>& Box0Max,
961  const Vector2<T>& Box1Min,
962  const Vector2<T>& Box1Max)
963 {
964  VERIFY_EXPR(Box0Max.x >= Box0Min.x && Box0Max.y >= Box0Min.y &&
965  Box1Max.x >= Box1Min.x && Box1Max.y >= Box1Min.y);
966  if (AllowTouch)
967  {
968  return !(Box0Min.x > Box1Max.x || Box1Min.x > Box0Max.x || Box0Min.y > Box1Max.y || Box1Min.y > Box0Max.y);
969  }
970  else
971  {
972  return !(Box0Min.x >= Box1Max.x || Box1Min.x >= Box0Max.x || Box0Min.y >= Box1Max.y || Box1Min.y >= Box0Max.y);
973  }
974 }
975 
976 
977 } // namespace Diligent
978 
979 namespace std
980 {
981 
982 template <>
983 struct hash<Diligent::Plane3D>
984 {
985  size_t operator()(const Diligent::Plane3D& Plane) const
986  {
987  return Diligent::ComputeHash(Plane.Normal, Plane.Distance);
988  }
989 };
990 
991 template <>
992 struct hash<Diligent::ViewFrustum>
993 {
994  size_t operator()(const Diligent::ViewFrustum& Frustum) const
995  {
996  return Diligent::ComputeHash(Frustum.LeftPlane, Frustum.RightPlane, Frustum.BottomPlane, Frustum.TopPlane, Frustum.NearPlane, Frustum.FarPlane);
997  }
998 };
999 
1000 template <>
1001 struct hash<Diligent::ViewFrustumExt>
1002 {
1003  size_t operator()(const Diligent::ViewFrustumExt& Frustum) const
1004  {
1005  auto Seed = Diligent::ComputeHash(static_cast<const Diligent::ViewFrustum&>(Frustum));
1006  for (int Corner = 0; Corner < _countof(Frustum.FrustumCorners); ++Corner)
1007  Diligent::HashCombine(Seed, Frustum.FrustumCorners[Corner]);
1008  return Seed;
1009  }
1010 };
1011 
1012 } // namespace std
Diligent::ViewFrustum::NUM_PLANES
@ NUM_PLANES
Definition: AdvancedMath.hpp:66
Diligent::FRUSTUM_PLANE_FLAG_TOP_PLANE
@ FRUSTUM_PLANE_FLAG_TOP_PLANE
Definition: AdvancedMath.hpp:321
std::hash< Diligent::ViewFrustum >::operator()
size_t operator()(const Diligent::ViewFrustum &Frustum) const
Definition: AdvancedMath.hpp:994
Diligent::Matrix4x4::_14
T _14
Definition: BasicMath.hpp:1073
Diligent::Plane3D::Normal
float3 Normal
Definition: AdvancedMath.hpp:43
BasicMath.hpp
Diligent::ViewFrustum::GetPlane
const Plane3D & GetPlane(PLANE_IDX Idx) const
Definition: AdvancedMath.hpp:76
Diligent::cross
Vector3< T > cross(const Vector3< T > &a, const Vector3< T > &b)
Definition: BasicMath.hpp:1731
Diligent::BoxVisibility::Invisible
@ Invisible
Diligent::Vector2::x
T x
Definition: BasicMath.hpp:80
Diligent::Matrix4x4::_34
T _34
Definition: BasicMath.hpp:1081
Diligent::Vector3::z
T z
Definition: BasicMath.hpp:267
Diligent::FRUSTUM_PLANE_FLAG_RIGHT_PLANE
@ FRUSTUM_PLANE_FLAG_RIGHT_PLANE
Definition: AdvancedMath.hpp:319
Diligent::Vector3< float >::MakeVector
static Vector3 MakeVector(const Y &vals)
Definition: BasicMath.hpp:440
Diligent::float3
Vector3< float > float3
Definition: BasicMath.hpp:1836
Diligent::ViewFrustum::PLANE_IDX
PLANE_IDX
Definition: AdvancedMath.hpp:58
Diligent::FRUSTUM_PLANE_FLAG_OPEN_NEAR
@ FRUSTUM_PLANE_FLAG_OPEN_NEAR
Definition: AdvancedMath.hpp:332
Diligent::GetBoxFarthestCorner
float3 GetBoxFarthestCorner(const float3 &Direction, const BoundBox &Box)
Returns the farthest bounding box corner along the given direction.
Definition: AdvancedMath.hpp:276
Diligent::Matrix4x4::_11
T _11
Definition: BasicMath.hpp:1070
Diligent::Matrix4x4::_21
T _21
Definition: BasicMath.hpp:1074
Diligent::Matrix4x4::_44
T _44
Definition: BasicMath.hpp:1085
Diligent::GetBoxVisibility
BoxVisibility GetBoxVisibility(const ViewFrustum &ViewFrustum, const BoundBox &Box, FRUSTUM_PLANE_FLAGS PlaneFlags=FRUSTUM_PLANE_FLAG_FULL_FRUSTUM)
Definition: AdvancedMath.hpp:341
Diligent::abs
Vector2< T > abs(const Vector2< T > &a)
Definition: BasicMath.hpp:1672
Diligent::Matrix4x4::Inverse
Matrix4x4 Inverse() const
Definition: BasicMath.hpp:1493
Diligent::IntersectRayBox3D
bool IntersectRayBox3D(const float3 &RayOrigin, const float3 &RayDirection, float3 BoxMin, float3 BoxMax, float &EnterDist, float &ExitDist)
Intersects a ray with 3D box and computes distances to intersections.
Definition: AdvancedMath.hpp:510
Diligent::operator==
bool operator==(const Plane3D &p1, const Plane3D &p2)
Definition: AdvancedMath.hpp:442
Diligent::length
auto length(const VectorType &a) -> decltype(dot(a, a))
Definition: BasicMath.hpp:1641
Diligent::Matrix4x4
Definition: BasicMath.hpp:71
std::hash< Diligent::Plane3D >::operator()
size_t operator()(const Diligent::Plane3D &Plane) const
Definition: AdvancedMath.hpp:985
Diligent::ViewFrustum::NearPlane
Plane3D NearPlane
Definition: AdvancedMath.hpp:73
Diligent::Box
Box.
Definition: GraphicsTypes.h:2407
Diligent::ViewFrustumExt::FrustumCorners
float3 FrustumCorners[8]
Definition: AdvancedMath.hpp:93
Diligent::Plane3D::Distance
float Distance
Definition: AdvancedMath.hpp:44
Diligent::Matrix4x4::_23
T _23
Definition: BasicMath.hpp:1076
Diligent::BoundBox::Transform
BoundBox Transform(const float4x4 &m) const
Definition: AdvancedMath.hpp:195
Diligent::ViewFrustum::LEFT_PLANE_IDX
@ LEFT_PLANE_IDX
Definition: AdvancedMath.hpp:60
Diligent::GetBoxVisibilityAgainstPlane
BoxVisibility GetBoxVisibilityAgainstPlane(const Plane3D &Plane, const BoundBox &Box)
Definition: AdvancedMath.hpp:286
Diligent::BoxVisibility
BoxVisibility
Definition: AdvancedMath.hpp:227
Diligent::clamp
T clamp(T val, T _min, T _max)
Definition: BasicMath.hpp:1700
std::min
Diligent::Vector2< T > min(const Diligent::Vector2< T > &Left, const Diligent::Vector2< T > &Right)
Definition: BasicMath.hpp:2289
Diligent::ViewFrustum::FarPlane
Plane3D FarPlane
Definition: AdvancedMath.hpp:74
Diligent::RasterizeTriangle
void RasterizeTriangle(Vector2< T > V0, Vector2< T > V1, Vector2< T > V2, TCallback Callback)
Rasterizes a triangle and calls the callback function for every sample covered.
Definition: AdvancedMath.hpp:858
Diligent::Vector3< float >
Diligent::Matrix4x4::_33
T _33
Definition: BasicMath.hpp:1080
Diligent::DEFINE_FLAG_ENUM_OPERATORS
DEFINE_FLAG_ENUM_OPERATORS(FRUSTUM_PLANE_FLAGS)
Diligent::max3
T max3(const T &x, const T &y, const T &z)
Definition: BasicMath.hpp:2036
Diligent::BoundBox::Max
float3 Max
Definition: AdvancedMath.hpp:192
Diligent::ViewFrustum::GetPlane
Plane3D & GetPlane(PLANE_IDX Idx)
Definition: AdvancedMath.hpp:83
Diligent::Matrix4x4::_32
T _32
Definition: BasicMath.hpp:1079
Diligent::FRUSTUM_PLANE_FLAG_NEAR_PLANE
@ FRUSTUM_PLANE_FLAG_NEAR_PLANE
Definition: AdvancedMath.hpp:322
Diligent::ViewFrustum::RightPlane
Plane3D RightPlane
Definition: AdvancedMath.hpp:70
Diligent::Box
struct Box Box
Definition: GraphicsTypes.h:2440
Diligent::ExtractViewFrustumPlanesFromMatrix
void ExtractViewFrustumPlanesFromMatrix(const float4x4 &Matrix, ViewFrustum &Frustum, bool bIsOpenGL)
Definition: AdvancedMath.hpp:106
Diligent::Matrix4x4::_31
T _31
Definition: BasicMath.hpp:1078
Diligent::BoundBox
Definition: AdvancedMath.hpp:189
Diligent::Vector3::y
T y
Definition: BasicMath.hpp:266
Diligent::TraceLineThroughGrid
void TraceLineThroughGrid(float2 f2Start, float2 f2End, int2 i2GridSize, TCallback Callback)
Traces a 2D line through the square cell grid and enumerates all cells the line touches.
Definition: AdvancedMath.hpp:669
std::hash< Diligent::ViewFrustumExt >::operator()
size_t operator()(const Diligent::ViewFrustumExt &Frustum) const
Definition: AdvancedMath.hpp:1003
Diligent::CheckBox2DBox2DOverlap
bool CheckBox2DBox2DOverlap(const Vector2< T > &Box0Min, const Vector2< T > &Box0Max, const Vector2< T > &Box1Min, const Vector2< T > &Box1Max)
Checks if two 2D-boxes overlap.
Definition: AdvancedMath.hpp:959
Diligent::ViewFrustum::BottomPlane
Plane3D BottomPlane
Definition: AdvancedMath.hpp:71
Diligent::ViewFrustum::RIGHT_PLANE_IDX
@ RIGHT_PLANE_IDX
Definition: AdvancedMath.hpp:61
Diligent::FRUSTUM_PLANE_FLAGS
FRUSTUM_PLANE_FLAGS
Definition: AdvancedMath.hpp:315
Diligent::Uint32
uint32_t Uint32
32-bit unsigned integer
Definition: BasicTypes.h:51
Diligent::float2
Vector2< float > float2
Definition: BasicMath.hpp:1835
Diligent::ComputeHash
std::size_t ComputeHash(const ArgsType &... Args)
Definition: HashUtils.hpp:57
Diligent::Vector2
Definition: BasicMath.hpp:74
Diligent::Matrix4x4::_12
T _12
Definition: BasicMath.hpp:1071
Diligent::ViewFrustum::LeftPlane
Plane3D LeftPlane
Definition: AdvancedMath.hpp:69
Diligent::Vector4< float >
Diligent::FRUSTUM_PLANE_FLAG_FAR_PLANE
@ FRUSTUM_PLANE_FLAG_FAR_PLANE
Definition: AdvancedMath.hpp:323
Diligent::min3
T min3(const T &x, const T &y, const T &z)
Definition: BasicMath.hpp:2042
Diligent::FRUSTUM_PLANE_FLAG_LEFT_PLANE
@ FRUSTUM_PLANE_FLAG_LEFT_PLANE
Definition: AdvancedMath.hpp:318
Diligent::Vector2::Recast
Vector2< Y > Recast() const
Definition: BasicMath.hpp:245
Diligent::ViewFrustum::TOP_PLANE_IDX
@ TOP_PLANE_IDX
Definition: AdvancedMath.hpp:63
Diligent::BoundBox::Min
float3 Min
Definition: AdvancedMath.hpp:191
Diligent::ViewFrustum::TopPlane
Plane3D TopPlane
Definition: AdvancedMath.hpp:72
Diligent::Matrix4x4::_42
T _42
Definition: BasicMath.hpp:1083
Diligent::BoxVisibility::Intersecting
@ Intersecting
Diligent::BoxVisibility::FullyVisible
@ FullyVisible
Diligent::IntersectRayTriangle
float IntersectRayTriangle(const float3 &V0, const float3 &V1, const float3 &V2, const float3 &RayOrigin, const float3 &RayDirection, bool CullBackFace=false)
Intersects a ray with the trianlge using Moller-Trumbore algorithm and returns the distance along the...
Definition: AdvancedMath.hpp:596
Diligent::FastFloor
T FastFloor(T x)
Definition: BasicMath.hpp:2093
Diligent::IntersectRayBox2D
bool IntersectRayBox2D(const float2 &RayOrigin, const float2 &RayDirection, float2 BoxMin, float2 BoxMax, float &EnterDist, float &ExitDist)
Intersects a 2D ray with the 2D axis-aligned bounding box and computes distances to intersections.
Definition: AdvancedMath.hpp:557
std
Definition: AdvancedMath.hpp:979
Diligent::ViewFrustumExt
Definition: AdvancedMath.hpp:91
std::max
Diligent::Vector2< T > max(const Diligent::Vector2< T > &Left, const Diligent::Vector2< T > &Right)
Definition: BasicMath.hpp:2261
Diligent::Matrix4x4::_24
T _24
Definition: BasicMath.hpp:1077
Diligent::IntersectRayAABB
bool IntersectRayAABB(const float3 &RayOrigin, const float3 &RayDirection, const BoundBox &AABB, float &EnterDist, float &ExitDist)
Intersects a ray with the axis-aligned bounding box and computes distances to intersections.
Definition: AdvancedMath.hpp:547
VERIFY_EXPR
#define VERIFY_EXPR(...)
Definition: DebugUtilities.hpp:79
Diligent::Matrix4x4::_22
T _22
Definition: BasicMath.hpp:1075
Diligent::Matrix4x4::_43
T _43
Definition: BasicMath.hpp:1084
_countof
#define _countof(_Array)
Definition: AndroidPlatformDefinitions.h:38
Diligent::FRUSTUM_PLANE_FLAG_BOTTOM_PLANE
@ FRUSTUM_PLANE_FLAG_BOTTOM_PLANE
Definition: AdvancedMath.hpp:320
Diligent::GetBoxNearestCorner
float3 GetBoxNearestCorner(const float3 &Direction, const BoundBox &Box)
Returns the nearest bounding box corner along the given direction.
Definition: AdvancedMath.hpp:265
Diligent::ViewFrustum
Definition: AdvancedMath.hpp:56
Diligent::IsPointInsideTriangle
bool IsPointInsideTriangle(const Vector2< T > &V0, const Vector2< T > &V1, const Vector2< T > &V2, const Vector2< T > &Point, bool AllowEdges)
Tests if a point is inside triangle.
Definition: AdvancedMath.hpp:754
Diligent::ViewFrustum::BOTTOM_PLANE_IDX
@ BOTTOM_PLANE_IDX
Definition: AdvancedMath.hpp:62
Diligent::FRUSTUM_PLANE_FLAG_FULL_FRUSTUM
@ FRUSTUM_PLANE_FLAG_FULL_FRUSTUM
Definition: AdvancedMath.hpp:325
Diligent::Matrix4x4::_41
T _41
Definition: BasicMath.hpp:1082
Diligent::FastCeil
T FastCeil(T x)
Definition: BasicMath.hpp:2108
Diligent::GetFrustumMinimumBoundingSphere
void GetFrustumMinimumBoundingSphere(float Proj_00, float Proj_11, float NearPlane, float FarPlane, float3 &Center, float &Radius)
Definition: AdvancedMath.hpp:486
Diligent::HermiteSpline
T HermiteSpline(T f0, T f1, T t0, T t1, Y x)
Definition: AdvancedMath.hpp:473
Diligent::Vector3::x
T x
Definition: BasicMath.hpp:265
Diligent::FRUSTUM_PLANE_FLAG_NONE
@ FRUSTUM_PLANE_FLAG_NONE
Definition: AdvancedMath.hpp:317
Diligent::dot
T dot(const Vector2< T > &a, const Vector2< T > &b)
Definition: BasicMath.hpp:1623
Diligent::HashCombine
void HashCombine(std::size_t &Seed, const T &Val)
Definition: HashUtils.hpp:44
Diligent::ViewFrustum::FAR_PLANE_IDX
@ FAR_PLANE_IDX
Definition: AdvancedMath.hpp:65
Diligent::GetPointToBoxDistance
float GetPointToBoxDistance(const BoundBox &BndBox, const float3 &Pos)
Definition: AdvancedMath.hpp:428
Diligent::Matrix4x4::_13
T _13
Definition: BasicMath.hpp:1072
Diligent::Plane3D
Definition: AdvancedMath.hpp:41
Diligent
The library uses Direct3D-style math:
Definition: AdvancedMath.hpp:37
Diligent::ViewFrustum::NEAR_PLANE_IDX
@ NEAR_PLANE_IDX
Definition: AdvancedMath.hpp:64
Diligent::Vector2::y
T y
Definition: BasicMath.hpp:81