Files
FlaxEngine/Source/Engine/Core/Math/BoundingFrustum.cpp
2020-12-07 23:40:54 +01:00

212 lines
5.7 KiB
C++

// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
#include "BoundingFrustum.h"
#include "BoundingBox.h"
#include "BoundingSphere.h"
#include "../Types/String.h"
String BoundingFrustum::ToString() const
{
return String::Format(TEXT("{}"), *this);
}
void BoundingFrustum::SetMatrix(const Matrix& matrix)
{
// Set matrix
_matrix = matrix;
// Source:
// http://www.chadvernon.com/blog/resources/directx9/frustum-culling/
// Left plane
_pLeft.Normal.X = matrix.M14 + matrix.M11;
_pLeft.Normal.Y = matrix.M24 + matrix.M21;
_pLeft.Normal.Z = matrix.M34 + matrix.M31;
_pLeft.D = matrix.M44 + matrix.M41;
_pLeft.Normalize();
// Right plane
_pRight.Normal.X = matrix.M14 - matrix.M11;
_pRight.Normal.Y = matrix.M24 - matrix.M21;
_pRight.Normal.Z = matrix.M34 - matrix.M31;
_pRight.D = matrix.M44 - matrix.M41;
_pRight.Normalize();
// Top plane
_pTop.Normal.X = matrix.M14 - matrix.M12;
_pTop.Normal.Y = matrix.M24 - matrix.M22;
_pTop.Normal.Z = matrix.M34 - matrix.M32;
_pTop.D = matrix.M44 - matrix.M42;
_pTop.Normalize();
// Bottom plane
_pBottom.Normal.X = matrix.M14 + matrix.M12;
_pBottom.Normal.Y = matrix.M24 + matrix.M22;
_pBottom.Normal.Z = matrix.M34 + matrix.M32;
_pBottom.D = matrix.M44 + matrix.M42;
_pBottom.Normalize();
// Near plane
_pNear.Normal.X = matrix.M13;
_pNear.Normal.Y = matrix.M23;
_pNear.Normal.Z = matrix.M33;
_pNear.D = matrix.M43;
_pNear.Normalize();
// Far plane
_pFar.Normal.X = matrix.M14 - matrix.M13;
_pFar.Normal.Y = matrix.M24 - matrix.M23;
_pFar.Normal.Z = matrix.M34 - matrix.M33;
_pFar.D = matrix.M44 - matrix.M43;
_pFar.Normalize();
}
Plane BoundingFrustum::GetPlane(int32 index) const
{
switch (index)
{
case 0:
return _pLeft;
case 1:
return _pRight;
case 2:
return _pTop;
case 3:
return _pBottom;
case 4:
return _pNear;
case 5:
return _pFar;
default:
return Plane();
}
}
void BoundingFrustum::GetCorners(Vector3 corners[8]) const
{
corners[0] = Get3PlanesInterPoint(_pNear, _pBottom, _pRight);
corners[1] = Get3PlanesInterPoint(_pNear, _pTop, _pRight);
corners[2] = Get3PlanesInterPoint(_pNear, _pTop, _pLeft);
corners[3] = Get3PlanesInterPoint(_pNear, _pBottom, _pLeft);
corners[4] = Get3PlanesInterPoint(_pFar, _pBottom, _pRight);
corners[5] = Get3PlanesInterPoint(_pFar, _pTop, _pRight);
corners[6] = Get3PlanesInterPoint(_pFar, _pTop, _pLeft);
corners[7] = Get3PlanesInterPoint(_pFar, _pBottom, _pLeft);
}
void BoundingFrustum::GetBox(BoundingBox& result) const
{
Vector3 corners[8];
GetCorners(corners);
BoundingBox::FromPoints(corners, 8, result);
}
void BoundingFrustum::GetSphere(BoundingSphere& result) const
{
Vector3 corners[8];
GetCorners(corners);
BoundingSphere::FromPoints(corners, 8, result);
}
float BoundingFrustum::GetWidthAtDepth(float depth) const
{
const float hAngle = PI / 2.0f - Math::Acos(Vector3::Dot(_pNear.Normal, _pLeft.Normal));
return Math::Tan(hAngle) * depth * 2.0f;
}
float BoundingFrustum::GetHeightAtDepth(float depth) const
{
const float vAngle = PI / 2.0f - Math::Acos(Vector3::Dot(_pNear.Normal, _pTop.Normal));
return Math::Tan(vAngle) * depth * 2.0f;
}
ContainmentType BoundingFrustum::Contains(const Vector3& point) const
{
PlaneIntersectionType result = PlaneIntersectionType::Front;
PlaneIntersectionType planeResult = PlaneIntersectionType::Front;
for (int i = 0; i < 6; i++)
{
switch (i)
{
case 0:
planeResult = _pNear.Intersects(point);
break;
case 1:
planeResult = _pFar.Intersects(point);
break;
case 2:
planeResult = _pLeft.Intersects(point);
break;
case 3:
planeResult = _pRight.Intersects(point);
break;
case 4:
planeResult = _pTop.Intersects(point);
break;
case 5:
planeResult = _pBottom.Intersects(point);
break;
}
switch (planeResult)
{
case PlaneIntersectionType::Back:
return ContainmentType::Disjoint;
case PlaneIntersectionType::Intersecting:
result = PlaneIntersectionType::Intersecting;
break;
}
}
switch (result)
{
case PlaneIntersectionType::Intersecting:
return ContainmentType::Intersects;
default:
return ContainmentType::Contains;
}
}
ContainmentType BoundingFrustum::Contains(const BoundingSphere& sphere) const
{
auto result = PlaneIntersectionType::Front;
auto planeResult = PlaneIntersectionType::Front;
for (int i = 0; i < 6; i++)
{
switch (i)
{
case 0:
planeResult = _pNear.Intersects(sphere);
break;
case 1:
planeResult = _pFar.Intersects(sphere);
break;
case 2:
planeResult = _pLeft.Intersects(sphere);
break;
case 3:
planeResult = _pRight.Intersects(sphere);
break;
case 4:
planeResult = _pTop.Intersects(sphere);
break;
case 5:
planeResult = _pBottom.Intersects(sphere);
break;
}
switch (planeResult)
{
case PlaneIntersectionType::Back:
return ContainmentType::Disjoint;
case PlaneIntersectionType::Intersecting:
result = PlaneIntersectionType::Intersecting;
break;
}
}
switch (result)
{
case PlaneIntersectionType::Intersecting:
return ContainmentType::Intersects;
default:
return ContainmentType::Contains;
}
}