1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include "[Frustum.h]"19 #include "[AABB.h]"20 #include "[Circle.h]"21 #include "../Math/MathFunc.h"22 #include "[Plane.h]"23 #include "[Line.h]"24 #include "[OBB.h]"25 #include "[Polyhedron.h]"26 #include "[Polygon.h]"27 #include "[Ray.h]"28 #include "[Sphere.h]"29 #include "[Capsule.h]"30 #include "[Triangle.h]"31 #include "[LineSegment.h]"32 #include "[PBVolume.h]"33 #include "../Math/float2.h"34 #include "../Math/float3x3.h"35 #include "../Math/float3x4.h"36 #include "../Math/float4x4.h"37 #include "../Math/float4.h"38 #include "../Math/Quat.h"39 #include "../Algorithm/Random/LCG.h"40 #include "../Algorithm/GJK.h"41 42 #ifdef MATH_ENABLE_STL_SUPPORT43 #include <iostream>44 #endif45 46 #if defined(MATH_TINYXML_INTEROP) && defined(MATH_CONTAINERLIB_SUPPORT)47 #include "Container/UString.h"48 #endif49 50 #if defined(MATH_SSE) && defined(MATH_AUTOMATIC_SSE)51 #include "../Math/float4_sse.h"52 #endif53 54 [MATH_BEGIN_NAMESPACE]55 56 [Frustum::Frustum]()57 :type([InvalidFrustum]),58 pos(vec::[nan]),59 front(vec::[nan]),60 up(vec::[nan]),61 nearPlaneDistance([FLOAT_NAN]),62 farPlaneDistance([FLOAT_NAN]),63 worldMatrix([float3x4]::[nan]),64 viewProjMatrix([float4x4]::[nan])65 {66         67         68 69 #ifdef MATH_USE_DIRECT3D70         projectiveSpace = [FrustumSpaceD3D];71 #elif defined(MATH_USE_OPENGL)72         projectiveSpace = [FrustumSpaceGL];73 #else74         projectiveSpace = [FrustumSpaceInvalid];75 #endif76 77 #ifdef MATH_LEFTHANDED_CAMERA78         handedness = [FrustumLeftHanded];79 #elif defined(MATH_RIGHTHANDED_CAMERA)80         handedness = [FrustumRightHanded];81 #else82         handedness = [FrustumHandednessInvalid];83 #endif84 }85 86 void [Frustum::SetKind]([FrustumProjectiveSpace] p, [FrustumHandedness] h)87 {88         projectiveSpace = p;89         handedness = h;90         if (up.[IsFinite]())91                 WorldMatrixChanged(); 92         ProjectionMatrixChanged();93 }94 95 void [Frustum::SetViewPlaneDistances](float n, float f)96 {97         nearPlaneDistance = n;98         farPlaneDistance = f;99         ProjectionMatrixChanged();100 }101 102 void [Frustum::SetFrame](const vec &p, const vec &f, const vec &u)103 {104         pos = p;105         front = f;106         up = u;107         WorldMatrixChanged();108 }109 110 void [Frustum::SetPos](const vec &p)111 {112         pos = p;113         WorldMatrixChanged();114 }115 116 void [Frustum::SetFront](const vec &f)117 {118         front = f;119         WorldMatrixChanged();120 }121 122 void [Frustum::SetUp](const vec &u)123 {124         up = u;125         WorldMatrixChanged();126 }127 128 void [Frustum::SetPerspective](float h, float v)129 {130         type = [PerspectiveFrustum];131         [horizontalFov] = h;132         [verticalFov] = v;133         ProjectionMatrixChanged();134 }135 136 void [Frustum::SetOrthographic](float w, float h)137 {138         type = [OrthographicFrustum];139         [orthographicWidth] = w;140         [orthographicHeight] = h;141         ProjectionMatrixChanged();142 }143 144 void Frustum::WorldMatrixChanged()145 {146         worldMatrix = [ComputeWorldMatrix]();147         [float3x4] viewMatrix = worldMatrix;148         viewMatrix.[InverseOrthonormal]();149         viewProjMatrix = projectionMatrix * viewMatrix;150 }151 152 void Frustum::ProjectionMatrixChanged()153 {154         projectionMatrix = [ComputeProjectionMatrix]();155         if ()156         {157                 [float3x4] viewMatrix = worldMatrix;158                 viewMatrix.[InverseOrthonormal]();159                 viewProjMatrix = projectionMatrix * viewMatrix;160         }161 }162 163 float [Frustum::AspectRatio]() const164 {165         return [Tan]([horizontalFov]*0.5f) / [Tan]([verticalFov]*0.5f);166 }167 168 void [Frustum::SetHorizontalFovAndAspectRatio](float hFov, float aspectRatio)169 {170         type = [PerspectiveFrustum];171         [horizontalFov] = hFov;172         [verticalFov] = 2.f * [Atan]([Tan](hFov*0.5f)/aspectRatio);173         ProjectionMatrixChanged();174 }175 176 void [Frustum::SetVerticalFovAndAspectRatio](float vFov, float aspectRatio)177 {178         type = [PerspectiveFrustum];179         [verticalFov] = vFov;180         [horizontalFov] = 2.f * [Atan]([Tan](vFov*0.5f)*aspectRatio);181         ProjectionMatrixChanged();182 }183 184 vec [Frustum::WorldRight]() const185 {186         if (handedness == [FrustumRightHanded])187                 return [Cross](front, up);188         else189                 return [Cross](up, front);190 }191 192 float [Frustum::NearPlaneWidth]() const193 {194         if (type == [PerspectiveFrustum])195                 return [Tan]([horizontalFov]*0.5f)*2.f * nearPlaneDistance;196         else197                 return [orthographicWidth];198 }199 200 float [Frustum::NearPlaneHeight]() const201 {202         if (type == [PerspectiveFrustum])203                 return [Tan]([verticalFov]*0.5f)*2.f * nearPlaneDistance;204         else205                 return [orthographicHeight];206 }207 208 [Plane] [Frustum::NearPlane]() const209 {210         return [Plane](pos + front * nearPlaneDistance, -front);211 }212 213 [Plane] [Frustum::FarPlane]() const214 {215         return [Plane](pos + front * farPlaneDistance, front);216 }217 218 [Plane] [Frustum::LeftPlane]() const219 {220         if (type == [PerspectiveFrustum])221         {222                 vec left = -[WorldRight]();223                 left.ScaleToLength([Tan]([horizontalFov]*0.5f));224                 vec leftSide = front + left;225                 vec leftSideNormal = ((handedness == [FrustumRightHanded]) ? [Cross](up, leftSide) : [Cross](leftSide, up)).Normalized();226                 return [Plane](pos, leftSideNormal);227         }228         else229         {230                 vec left = -[WorldRight]();231                 return [Plane]([NearPlanePos](-1.f, 0.f), left.[Normalized]());232         }233 }234 235 [Plane] [Frustum::RightPlane]() const236 {237         if (type == [PerspectiveFrustum])238         {239                 vec right = [WorldRight]();240                 right.ScaleToLength([Tan]([horizontalFov]*0.5f));241                 vec rightSide = front + right;242                 vec rightSideNormal = ((handedness == [FrustumRightHanded]) ? [Cross](rightSide, up) : [Cross](up, rightSide)).Normalized();243                 return [Plane](pos, rightSideNormal);244         }245         else246         {247                 vec right = [WorldRight]();248                 return [Plane]([NearPlanePos](1.f, 0.f), right.[Normalized]());249         }250 }251 252 [Plane] [Frustum::TopPlane]() const253 {254         if (type == [PerspectiveFrustum])255         {256                 vec topSide = front + [Tan]([verticalFov] * 0.5f) * up;257                 vec right = [WorldRight]();258                 vec topSideNormal = ((handedness == [FrustumRightHanded]) ? [Cross](right, topSide) : [Cross](topSide, right)).Normalized();259                 return [Plane](pos, topSideNormal);260         }261         else262         {263                 return [Plane]([NearPlanePos](0.f, 1.f), up);264         }265 }266 267 [Plane] [Frustum::BottomPlane]() const268 {269         if (type == [PerspectiveFrustum])270         {271                 vec bottomSide = front - [Tan]([verticalFov] * 0.5f) * up;272                 vec left = -[WorldRight]();273                 vec bottomSideNormal = ((handedness == [FrustumRightHanded]) ? [Cross](left, bottomSide) : [Cross](bottomSide, left)).Normalized();274                 return [Plane](pos, bottomSideNormal);275         }276         else277         {278                 return [Plane]([NearPlanePos](0.f, -1.f), -up);279         }280 }281 282 void [Frustum::SetWorldMatrix](const [float3x4] &worldTransform)283 {284         pos = [POINT_VEC](worldTransform.[TranslatePart]());285         if (handedness == [FrustumRightHanded])286                 front = -[DIR_VEC](worldTransform.[Col](2)); 287         else288                 front = [DIR_VEC](worldTransform.[Col](2)); 289         up = [DIR_VEC](worldTransform.[Col](1)); 290         [assume1](pos.[IsFinite](), pos);291         [assume2](up.IsNormalized(1[e]-3f), up, up.Length());292         [assume2](front.IsNormalized(1[e]-3f), front, front.Length());293         [assume3](up.IsPerpendicular(front), up, front, up.Dot(front));294         [assume](worldTransform.[IsColOrthogonal3]()); 295         [assume]([EqualAbs](worldTransform.[Determinant](), 1.f)); 296 297         298         worldMatrix = worldTransform;299 }300 301 [float3x4] [Frustum::ComputeWorldMatrix]() const302 {303         [assume1](pos.[IsFinite](), pos);304         [assume2](up.IsNormalized(1[e]-3f), up, up.Length());305         [assume2](front.IsNormalized(1[e]-3f), front, front.Length());306         [assume3](up.IsPerpendicular(front), up, front, up.Dot(front));307         [float3x4] m;308         m.[SetCol](0, [DIR_TO_FLOAT3]([WorldRight]().Normalized()));309         m.SetCol(1, [DIR_TO_FLOAT3](up));310         if (handedness == [FrustumRightHanded])311                 m.SetCol(2, [DIR_TO_FLOAT3](-front)); 312         else313                 m.SetCol(2, [DIR_TO_FLOAT3](front)); 314         m.SetCol(3, [POINT_TO_FLOAT3](pos));315         [assume](!m.HasNegativeScale());316         return m;317 }318 319 [float3x4] [Frustum::ComputeViewMatrix]() const320 {321         [float3x4] world = [ComputeWorldMatrix]();322         world.[InverseOrthonormal]();323         return world;324 }325 326 [float4x4] [Frustum::ComputeViewProjMatrix]() const327 {328         return [ComputeProjectionMatrix]() * [ComputeViewMatrix]();329 }330 331 [float4x4] [Frustum::ComputeProjectionMatrix]() const332 {333         if (type == [InvalidFrustum] || projectiveSpace == [FrustumSpaceInvalid])334                 return [float4x4::nan];335         [assume](type == [PerspectiveFrustum] || type == [OrthographicFrustum]);336         [assume](projectiveSpace == [FrustumSpaceGL] || projectiveSpace == [FrustumSpaceD3D]);337         [assume](handedness == [FrustumLeftHanded] || handedness == [FrustumRightHanded]);338         if (type == [PerspectiveFrustum])339         {340                 if (projectiveSpace == [FrustumSpaceGL])341                 {342                         if (handedness == [FrustumRightHanded])343                                 return [float4x4::OpenGLPerspProjRH](nearPlaneDistance, farPlaneDistance, [NearPlaneWidth](), [NearPlaneHeight]());344                         else if (handedness == [FrustumLeftHanded])345                                 return [float4x4::OpenGLPerspProjLH](nearPlaneDistance, farPlaneDistance, [NearPlaneWidth](), [NearPlaneHeight]());346                 }347                 else if (projectiveSpace == [FrustumSpaceD3D])348                 {349                         if (handedness == [FrustumRightHanded])350                                 return [float4x4::D3DPerspProjRH](nearPlaneDistance, farPlaneDistance, [NearPlaneWidth](), [NearPlaneHeight]());351                         else if (handedness == [FrustumLeftHanded])352                                 return [float4x4::D3DPerspProjLH](nearPlaneDistance, farPlaneDistance, [NearPlaneWidth](), [NearPlaneHeight]());353                 }354         }355         else if (type == [OrthographicFrustum])356         {357                 if (projectiveSpace == [FrustumSpaceGL])358                 {359                         if (handedness == [FrustumRightHanded])360                                 return [float4x4::OpenGLOrthoProjRH](nearPlaneDistance, farPlaneDistance, [orthographicWidth], [orthographicHeight]);361                         else if (handedness == [FrustumLeftHanded])362                                 return [float4x4::OpenGLOrthoProjLH](nearPlaneDistance, farPlaneDistance, [orthographicWidth], [orthographicHeight]);363                 }364                 else if (projectiveSpace == [FrustumSpaceD3D])365                 {366                         if (handedness == [FrustumRightHanded])367                                 return [float4x4::D3DOrthoProjRH](nearPlaneDistance, farPlaneDistance, [orthographicWidth], [orthographicHeight]);368                         else if (handedness == [FrustumLeftHanded])369                                 return [float4x4::D3DOrthoProjLH](nearPlaneDistance, farPlaneDistance, [orthographicWidth], [orthographicHeight]);370                 }371         }372 #ifndef OPTIMIZED_RELEASE373         [LOGE]("Not all values of Frustum were initialized properly! Please initialize correctly before calling Frustum::ProjectionMatrix()!");374 #endif375         return [float4x4::nan];376 }377 378 vec [Frustum::NearPlanePos](float x, float y) const379 {380         [assume](type == [PerspectiveFrustum] || type == [OrthographicFrustum]);381 382         if (type == [PerspectiveFrustum])383         {384                 float frontPlaneHalfWidth = [Tan]([horizontalFov]*0.5f)*nearPlaneDistance;385                 float frontPlaneHalfHeight = [Tan]([verticalFov]*0.5f)*nearPlaneDistance;386                 x = x * frontPlaneHalfWidth; 387                 y = y * frontPlaneHalfHeight;  388                 vec right = [WorldRight]();389                 return pos + front * nearPlaneDistance + x * right + y * up;390         }391         else392         {393                 vec right = [WorldRight]();394                 return pos + front * nearPlaneDistance395                                    + x * [orthographicWidth] * 0.5f * right396                                    + y * [orthographicHeight] * 0.5f * up;397         }398 }399 400 vec [Frustum::NearPlanePos](const [float2] &point) const401 {402         return [NearPlanePos](point.[x], point.[y]);403 }404 405 vec [Frustum::FarPlanePos](float x, float y) const406 {407         [assume](type == [PerspectiveFrustum] || type == [OrthographicFrustum]);408 409         if (type == [PerspectiveFrustum])410         {411                 float farPlaneHalfWidth = [Tan]([horizontalFov]*0.5f)*farPlaneDistance;412                 float farPlaneHalfHeight = [Tan]([verticalFov]*0.5f)*farPlaneDistance;413                 x = x * farPlaneHalfWidth;414                 y = y * farPlaneHalfHeight;415                 vec right = [WorldRight]();416                 return pos + front * farPlaneDistance + x * right + y * up;417         }418         else419         {420                 vec right = [WorldRight]();421                 return pos + front * farPlaneDistance422                                    + x * [orthographicWidth] * 0.5f * right423                                    + y * [orthographicHeight] * 0.5f * up;424         }425 }426 427 vec [Frustum::FarPlanePos](const [float2] &point) const428 {429         return [FarPlanePos](point.[x], point.[y]);430 }431 432 [float2] [Frustum::ViewportToScreenSpace](float x, float y, int screenWidth, int screenHeight)433 {434         return [float2]((x + 1.f) * 0.5f * (screenWidth-1.f), (1.f - y) * 0.5f * (screenHeight-1.f));435 }436 437 [float2] [Frustum::ViewportToScreenSpace](const [float2] &point, int screenWidth, int screenHeight)438 {439         return [ViewportToScreenSpace](point.[x], point.[y], screenWidth, screenHeight);440 }441 442 [float2] [Frustum::ScreenToViewportSpace](float x, float y, int screenWidth, int screenHeight)443 {444         return [float2](x * 2.f / (screenWidth-1.f) - 1.f, 1.f - y * 2.f / (screenHeight - 1.f));445 }446 447 [float2] [Frustum::ScreenToViewportSpace](const [float2] &point, int screenWidth, int screenHeight)448 {449         return [ScreenToViewportSpace](point.[x], point.[y], screenWidth, screenHeight);450 }451 452 [Ray] [Frustum::UnProject](float x, float y) const453 {454         [assume1](x >= -1.f, x);455         [assume1](x <= 1.f, x);456         [assume1](y >= -1.f, y);457         [assume1](y <= 1.f, y);458         if (type == [PerspectiveFrustum])459         {460                 vec nearPlanePos = [NearPlanePos](x, y);461                 return [Ray](pos, (nearPlanePos - pos).Normalized());462         }463         else464                 return [UnProjectFromNearPlane](x, y);465 }466 467 [LineSegment] [Frustum::UnProjectLineSegment](float x, float y) const468 {469         vec nearPlanePos = [NearPlanePos](x, y);470         vec farPlanePos = [FarPlanePos](x, y);471         return [LineSegment](nearPlanePos, farPlanePos);472 }473 474 [Ray] [Frustum::UnProjectFromNearPlane](float x, float y) const475 {476         return [UnProjectLineSegment](x, y).[ToRay]();477 }478 479 vec [Frustum::PointInside](float x, float y, float z) const480 {481         [assume](z >= 0.f);482         [assume](z <= 1.f);483         return [UnProjectLineSegment](x, y).[GetPoint](z);484 }485 486 vec [Frustum::Project](const vec &point) const487 {488         [float4] projectedPoint = [ViewProjMatrix]().[Mul]([POINT_TO_FLOAT4](point));489         projectedPoint.[NormalizeW](); 490         return [FLOAT4_TO_POINT](projectedPoint);491 }492 493 bool [Frustum::Contains](const vec &point) const494 {495 #if defined(MATH_AUTOMATIC_SSE) && defined(MATH_SSE)496         497         vec projected = [Project](point);498         simd4f a = abs_ps(projected);499         simd4f y = yyyy_ps(a);500         a = max_ps(a, y);501         y = zzzz_ps(a);502         a = max_ps(a, y);503         const float [eps] = 1[e]-3f;504         return _mm_cvtss_f32(a) <= 1.f + eps &&505                 (projectiveSpace == [FrustumSpaceGL] || s4f_z(projected) >= -[eps]);506 #else507         508         const float eps = 1[e]-3f;509         const float pos = 1.f + [eps];510         const float neg = -pos;511         vec projected = [Project](point);512         if (projectiveSpace == [FrustumSpaceD3D])513         {514                 return neg <= projected.x && projected.x <= pos &&515                         neg <= projected.y && projected.y <= pos &&516                         -eps <= projected.z && projected.z <= pos;517         }518         else if (projectiveSpace == [FrustumSpaceGL])519         {520                 return neg <= projected.x && projected.x <= pos &&521                         neg <= projected.y && projected.y <= pos &&522                         neg <= projected.z && projected.z <= pos;523         }524         else525         {526 #ifndef OPTIMIZED_RELEASE527 528                 [LOGE]("Not all values of Frustum were initialized properly! Please initialize correctly before calling Frustum::Contains()!");529 #endif530                 return false;531         }532 #endif533 }534 535 bool [Frustum::Contains](const [LineSegment] &lineSegment) const536 {537 #if defined(MATH_AUTOMATIC_SSE) && defined(MATH_SSE)538         539         vec pa = [Project](lineSegment.[a]);540         simd4f a = abs_ps(pa);541         vec pb = [Project](lineSegment.[b]);542         simd4f b = abs_ps(pb);543         a = max_ps(a, b);544         simd4f y = yyyy_ps(a);545         a = max_ps(a, y);546         y = zzzz_ps(a);547         a = max_ps(a, y);548         const float eps = 1[e]-3f;549         return _mm_cvtss_f32(a) <= 1.f + eps &&550                 (projectiveSpace == [FrustumSpaceGL] || s4f_z(min_ps(pa, pb)) >= -[eps]);551 #else552         553         return [Contains](lineSegment.[a]) && [Contains](lineSegment.[b]);554 #endif555 }556 557 bool [Frustum::Contains](const [Triangle] &triangle) const558 {559 #if defined(MATH_AUTOMATIC_SSE) && defined(MATH_SSE)560         561         vec pa = [Project](triangle.[a]);562         simd4f a = abs_ps(pa);563         vec pb = [Project](triangle.[b]);564         simd4f b = abs_ps(pb);565         a = max_ps(a, b);566         vec pc = [Project](triangle.[c]);567         simd4f c = abs_ps(pc);568         a = max_ps(a, c);569         simd4f y = yyyy_ps(a);570         a = max_ps(a, y);571         y = zzzz_ps(a);572         a = max_ps(a, y);573         const float eps = 1[e]-3f;574         return _mm_cvtss_f32(a) <= 1.f + eps &&575                 (projectiveSpace == [FrustumSpaceGL] || s4f_z(min_ps(min_ps(pa, pb), pc)) >= -[eps]);576 #else577         578         return [Contains](triangle.[a]) && [Contains](triangle.[b]) && [Contains](triangle.[c]);579 #endif580 }581 582 bool [Frustum::Contains](const [Polygon] &polygon) const583 {584         for(int i = 0; i < polygon.[NumVertices](); ++i)585                 if ())586                         return false;587         return true;588 }589 590 bool [Frustum::Contains](const [AABB] &aabb) const591 {592         for(int i = 0; i < 8; ++i)593                 if ())594                         return false;595 596         return true;597 }598 599 bool [Frustum::Contains](const [OBB] &obb) const600 {601         for(int i = 0; i < 8; ++i)602                 if ())603                         return false;604 605         return true;606 }607 608 bool [Frustum::Contains](const [Frustum] &frustum) const609 {610         for(int i = 0; i < 8; ++i)611                 if ())612                         return false;613 614         return true;615 }616 617 bool [Frustum::Contains](const [Polyhedron] &polyhedron) const618 {619         [assume](polyhedron.[IsClosed]());620         for(int i = 0; i < polyhedron.[NumVertices](); ++i)621                 if ())622                         return false;623 624         return true;625 }626 627 vec [Frustum::ClosestPoint](const vec &point) const628 {629         if (type == [OrthographicFrustum])630         {631                 float frontHalfSize = (farPlaneDistance - nearPlaneDistance) * 0.5f;632                 float halfWidth = [orthographicWidth] * 0.5f;633                 float halfHeight = [orthographicHeight] * 0.5f;634                 vec frustumCenter = pos + (frontHalfSize + nearPlaneDistance) * front;635                 vec right = [Cross](front, up);636                 [assert](right.IsNormalized());637                 vec [d] = point - frustumCenter;638                 vec closestPoint = frustumCenter;639 #if defined(MATH_AUTOMATIC_SSE) && defined(MATH_SSE)640                 641                 simd4f z = set1_ps(frontHalfSize);642                 closestPoint = add_ps(closestPoint, mul_ps(max_ps(min_ps(dot4_ps(d.v, front.v), z), negate_ps(z)), front.v));643                 simd4f y = set1_ps(halfHeight);644                 closestPoint = add_ps(closestPoint, mul_ps(max_ps(min_ps(dot4_ps(d.v, up.v), y), negate_ps(y)), up.v));645                 simd4f x = set1_ps(halfWidth);646                 closestPoint = add_ps(closestPoint, mul_ps(max_ps(min_ps(dot4_ps(d.v, right.v), x), negate_ps(x)), right.v));647 #else648                 649                 closestPoint += [Clamp]([Dot](d, front), -frontHalfSize, frontHalfSize) * front;650                 closestPoint += [Clamp]([Dot](d, right), -halfWidth, halfWidth) * right;651                 closestPoint += [Clamp]([Dot](d, up), -halfHeight, halfHeight) * up;652 #endif653                 return closestPoint;654         }655         else656         {657                 658                 return [ToPolyhedron]().[ClosestPoint](point);659         }660 661 662 663 }664 665 float [Frustum::Distance](const vec &point) const666 {667         vec pt = [ClosestPoint](point);668         return pt.Distance(point);669 }670 671 bool [Frustum::IsFinite]() const672 {673         return pos.IsFinite() && front.IsFinite() && up.IsFinite() && [MATH_NS::IsFinite](nearPlaneDistance)674                 && [MATH_NS::IsFinite](farPlaneDistance) && [MATH_NS::IsFinite]([horizontalFov]) && [MATH_NS::IsFinite]([verticalFov]);675 }676 677 [Plane] [Frustum::GetPlane](int faceIndex) const678 {679         [assume](0 <= faceIndex && faceIndex <= 5);680         switch(faceIndex)681         {682                 default: 683                 case 0: return [NearPlane]();684                 case 1: return [FarPlane]();685                 case 2: return [LeftPlane]();686                 case 3: return [RightPlane]();687                 case 4: return [TopPlane]();688                 case 5: return [BottomPlane]();689         }690 }691 692 float [Frustum::Volume]() const693 {694         return [ToPolyhedron]().[Volume]();695 }696 697 vec [Frustum::FastRandomPointInside]([LCG] &rng) const698 {699         float f1 = rng.[Float](-1.f, 1.f);700         float f2 = rng.[Float](-1.f, 1.f);701         float f3 = rng.[Float](0.f, 1.f);702         return [PointInside](f1, f2, f3);703 }704 705 vec [Frustum::UniformRandomPointInside]([LCG] &rng) const706 {707         if (type == [OrthographicFrustum])708                 return [FastRandomPointInside](rng);709         else710         {711                 [OBB] o = [MinimalEnclosingOBB]();712                 for(int numTries = 0; numTries < 1000; ++numTries)713                 {714                         vec pt = o.[RandomPointInside](rng);715                         if ([Contains](pt))716                                 return pt;717                 }718                 [LOGW]("Rejection sampling failed in Frustum::UniformRandomPointInside! Producing a non-uniformly distributed point inside the frustum!");719                 return [FastRandomPointInside](rng);720         }721 }722 723 void [Frustum::Translate](const vec &offset)724 {725         pos += offset;726 }727 728 void [Frustum::Transform](const [float3x3] &transform)729 {730         [assume](transform.[HasUniformScale]());731         pos = transform * pos;732         front = transform * front;733         float scaleFactor = front.Normalize();734         up = (transform * up).Normalized();735         nearPlaneDistance *= scaleFactor;736         farPlaneDistance *= scaleFactor;737         if (type == [OrthographicFrustum])738         {739                 [orthographicWidth] *= scaleFactor;740                 [orthographicHeight] *= scaleFactor;741         }742 }743 744 void [Frustum::Transform](const [float3x4] &transform)745 {746         [assume](transform.[HasUniformScale]());747         pos = transform.[MulPos](pos);748         front = transform.[MulDir](front);749         float scaleFactor = front.[Normalize]();750         up = transform.[MulDir](up).[Normalized]();751         nearPlaneDistance *= scaleFactor;752         farPlaneDistance *= scaleFactor;753         if (type == [OrthographicFrustum])754         {755                 [orthographicWidth] *= scaleFactor;756                 [orthographicHeight] *= scaleFactor;757         }758 }759 760 void [Frustum::Transform](const [float4x4] &transform)761 {762         [assume](transform.[Row](3).[Equals](0,0,0,1));763         [Transform](transform.[Float3x4Part]());764 }765 766 void [Frustum::Transform](const [Quat] &transform)767 {768         [Transform](transform.[ToFloat3x3]());769 }770 771 void [Frustum::GetPlanes]([Plane] *outArray) const772 {773         [assume](outArray);774 #ifndef MATH_ENABLE_INSECURE_OPTIMIZATIONS775         if (!outArray)776                 return;777 #endif778         for(int i = 0; i < 6; ++i)779                 outArray[i] = [GetPlane](i);780 }781 782 vec [Frustum::CenterPoint]() const783 {784         return pos + (nearPlaneDistance + farPlaneDistance) * 0.5f * front;785 }786 787 void [Frustum::GetCornerPoints](vec *outPointArray) const788 {789         [assume](outPointArray);790 #ifndef MATH_ENABLE_INSECURE_OPTIMIZATIONS791         if (!outPointArray)792                 return;793 #endif794 795         if (type == [PerspectiveFrustum])796         {797                 float tanhfov = [Tan]([horizontalFov]*0.5f);798                 float tanvfov = [Tan]([verticalFov]*0.5f);799                 float frontPlaneHalfWidth = tanhfov*nearPlaneDistance;800                 float frontPlaneHalfHeight = tanvfov*nearPlaneDistance;801                 float farPlaneHalfWidth = tanhfov*farPlaneDistance;802                 float farPlaneHalfHeight = tanvfov*farPlaneDistance;803 804                 vec right = [WorldRight]();805 806                 vec nearCenter = pos + front * nearPlaneDistance;807                 vec nearHalfWidth = frontPlaneHalfWidth*right;808                 vec nearHalfHeight = frontPlaneHalfHeight*up;809                 outPointArray[0] = nearCenter - nearHalfWidth - nearHalfHeight;810                 outPointArray[1] = nearCenter + nearHalfWidth - nearHalfHeight;811                 outPointArray[2] = nearCenter - nearHalfWidth + nearHalfHeight;812                 outPointArray[3] = nearCenter + nearHalfWidth + nearHalfHeight;813 814                 vec farCenter = pos + front * farPlaneDistance;815                 vec farHalfWidth = farPlaneHalfWidth*right;816                 vec farHalfHeight = farPlaneHalfHeight*up;817                 outPointArray[4] = farCenter - farHalfWidth - farHalfHeight;818                 outPointArray[5] = farCenter + farHalfWidth - farHalfHeight;819                 outPointArray[6] = farCenter - farHalfWidth + farHalfHeight;820                 outPointArray[7] = farCenter + farHalfWidth + farHalfHeight;821         }822         else823         {824                 vec right = [WorldRight]();825                 vec nearCenter = pos + front * nearPlaneDistance;826                 vec farCenter = pos + front * farPlaneDistance;827                 vec halfWidth = [orthographicWidth] * 0.5f * right;828                 vec halfHeight = [orthographicHeight] * 0.5f * up;829 830                 outPointArray[0] = nearCenter - halfWidth - halfHeight;831                 outPointArray[1] = nearCenter + halfWidth - halfHeight;832                 outPointArray[2] = nearCenter - halfWidth + halfHeight;833                 outPointArray[3] = nearCenter + halfWidth + halfHeight;834                 outPointArray[4] = farCenter - halfWidth - halfHeight;835                 outPointArray[5] = farCenter + halfWidth - halfHeight;836                 outPointArray[6] = farCenter - halfWidth + halfHeight;837                 outPointArray[7] = farCenter + halfWidth + halfHeight;838         }839 }840 841 [LineSegment] [Frustum::Edge](int edgeIndex) const842 {843         [assume](0 <= edgeIndex && edgeIndex <= 11);844         switch(edgeIndex)845         {846                 default: 847                 case 0: return [LineSegment]([CornerPoint](0), [CornerPoint](1));848                 case 1: return [LineSegment]([CornerPoint](0), [CornerPoint](2));849                 case 2: return [LineSegment]([CornerPoint](0), [CornerPoint](4));850                 case 3: return [LineSegment]([CornerPoint](1), [CornerPoint](3));851                 case 4: return [LineSegment]([CornerPoint](1), [CornerPoint](5));852                 case 5: return [LineSegment]([CornerPoint](2), [CornerPoint](3));853                 case 6: return [LineSegment]([CornerPoint](2), [CornerPoint](6));854                 case 7: return [LineSegment]([CornerPoint](3), [CornerPoint](7));855                 case 8: return [LineSegment]([CornerPoint](4), [CornerPoint](5));856                 case 9: return [LineSegment]([CornerPoint](4), [CornerPoint](6));857                 case 10: return [LineSegment]([CornerPoint](5), [CornerPoint](7));858                 case 11: return [LineSegment]([CornerPoint](6), [CornerPoint](7));859         }860 }861 862 vec [Frustum::CornerPoint](int cornerIndex) const863 {864         [assume](0 <= cornerIndex && cornerIndex <= 7);865         switch(cornerIndex)866         {867                 default: 868                 case 0: return [NearPlanePos](-1, -1);869                 case 1: return [FarPlanePos](-1, -1);870                 case 2: return [NearPlanePos](-1, 1);871                 case 3: return [FarPlanePos](-1, 1);872                 case 4: return [NearPlanePos](1, -1);873                 case 5: return [FarPlanePos](1, -1);874                 case 6: return [NearPlanePos](1, 1);875                 case 7: return [FarPlanePos](1, 1);876         }877 }878 879 vec [Frustum::ExtremePoint](const vec &direction, float &projectionDistance) const880 {881         vec corners[8];882         [GetCornerPoints](corners);883         vec mostExtreme = [vec::nan];884         projectionDistance = -[FLOAT_INF];885         for(int i = 0; i < 8; ++i)886         {887                 float d = [Dot](direction, corners[i]);888                 if (d > projectionDistance)889                 {890                         projectionDistance = [d];891                         mostExtreme = corners[i];892                 }893         }894         return mostExtreme;895 }896 897 void [Frustum::ProjectToAxis](const vec &direction, float &outMin, float &outMax) const898 {899         vec corners[8];900         [GetCornerPoints](corners);901         outMax = -[FLOAT_INF];902         outMin = [FLOAT_INF];903         for(int i = 0; i < 8; ++i)904         {905                 float d = [Dot](direction, corners[i]);906                 outMax = [Max](outMax, d);907                 outMin = [Min](outMin, d);908         }909 }910 911 int [Frustum::UniqueFaceNormals](vec *out) const912 {913         if (type == [PerspectiveFrustum])914         {915                 out[0] = front;916                 out[1] = [LeftPlane]().[normal];917                 out[2] = [RightPlane]().[normal];918                 out[3] = [TopPlane]().[normal];919                 out[4] = [BottomPlane]().[normal];920                 return 5;921         }922         else923         {924                 out[0] = front;925                 out[1] = up;926                 out[2] = [Cross](front, up);927                 return 3;928         }929 }930 931 int [Frustum::UniqueEdgeDirections](vec *out) const932 {933         if (type == [PerspectiveFrustum])934         {935                 out[0] = [NearPlanePos](-1, -1) - [NearPlanePos](1, -1);936                 out[1] = [NearPlanePos](-1, -1) - [NearPlanePos](-1, 1);937                 out[2] = [FarPlanePos](-1, -1) - [NearPlanePos](-1, -1);938                 out[3] = [FarPlanePos]( 1, -1) - [NearPlanePos]( 1, -1);939                 out[4] = [FarPlanePos](-1,  1) - [NearPlanePos](-1,  1);940                 out[5] = [FarPlanePos]( 1,  1) - [NearPlanePos]( 1,  1);941                 return 6;942         }943         else944         {945                 out[0] = front;946                 out[1] = up;947                 out[2] = [Cross](front, up);948                 return 3;949         }950 }951 952 [AABB] [Frustum::MinimalEnclosingAABB]() const953 {954         [AABB] aabb;955         aabb.[SetNegativeInfinity]();956         for(int i = 0; i < 8; ++i)957                 aabb.[Enclose]([CornerPoint](i));958         return aabb;959 }960 961 [OBB] [Frustum::MinimalEnclosingOBB](float expandGuardband) const962 {963         [assume]([IsFinite]());964         [assume](front.IsNormalized());965         [assume](up.IsNormalized());966 967         [OBB] obb;968         obb.[pos] = pos + (nearPlaneDistance + farPlaneDistance) * 0.5f * front;969         obb.axis[1] = up;970         obb.axis[2] = -front;971         obb.axis[0] = [Cross](obb.axis[1], obb.axis[2]);972         obb.r = [vec::zero];973         for(int i = 0; i < 8; ++i)974                 obb.Enclose([CornerPoint](i));975 976         977         978         obb.r.x += expandGuardband;979         obb.r.y += expandGuardband;980         obb.r.z += expandGuardband;981         return obb;982 }983 984 [Polyhedron] [Frustum::ToPolyhedron]() const985 {986         987 988         [Polyhedron] p;989         990         991         for(int i = 0; i < 8; ++i)992                 p.[v].push_back([CornerPoint](i));993 994         995         996         const int faces[6][4] =997         {998                 { 0, 4, 6, 2 }, 999                 { 1, 3, 7, 5 }, 1000                 { 0, 2, 3, 1 }, 1001                 { 4, 5, 7, 6 }, 1002                 { 7, 3, 2, 6 }, 1003                 { 0, 1, 5, 4 }, 1004         };1005 1006         for(int f = 0; f < 6; ++f)1007         {1008                 [Polyhedron::Face] face;1009                 if (this->handedness == [FrustumLeftHanded])1010                 {1011                         for(int v = 0; v < 4; ++v)1012                                 face.[v].push_back(faces[f][3-v]);1013                 }1014                 else1015                 {1016                         for(int v = 0; v < 4; ++v)1017                                 face.[v].push_back(faces[f][v]);1018                 }1019                 p.[f].push_back(face);1020         }1021 1022         return p;1023 }1024 1025 [PBVolume<6>] [Frustum::ToPBVolume]() const1026 {1027         [PBVolume<6>] frustumVolume;1028         frustumVolume.[p][0] = [NearPlane]();1029         frustumVolume.[p][1] = [LeftPlane]();1030         frustumVolume.[p][2] = [RightPlane]();1031         frustumVolume.[p][3] = [TopPlane]();1032         frustumVolume.[p][4] = [BottomPlane]();1033         frustumVolume.[p][5] = [FarPlane]();1034 1035         return frustumVolume;1036 }1037 1038 bool [Frustum::Intersects](const [Ray] &ray) const1039 {1040 1041         return this->[ToPolyhedron]().[Intersects](ray);1042 }1043 1044 bool [Frustum::Intersects](const [Line] &line) const1045 {1046 1047         return this->[ToPolyhedron]().[Intersects](line);1048 }1049 1050 bool [Frustum::Intersects](const [LineSegment] &lineSegment) const1051 {1052         return [GJKIntersect](*this, lineSegment);1053 }1054 1055 bool [Frustum::Intersects](const [AABB] &aabb) const1056 {1057         return [GJKIntersect](*this, aabb);1058 }1059 1060 bool [Frustum::Intersects](const [OBB] &obb) const1061 {1062         return [GJKIntersect](*this, obb);1063 }1064 1065 bool [Frustum::Intersects](const [Plane] &plane) const1066 {1067         return plane.[Intersects](*this);1068 }1069 1070 bool [Frustum::Intersects](const [Triangle] &triangle) const1071 {1072         return [GJKIntersect](*this, triangle);1073 }1074 1075 bool [Frustum::Intersects](const [Polygon] &polygon) const1076 {1077         return polygon.[Intersects](*this);1078 }1079 1080 bool [Frustum::Intersects](const [Sphere] &sphere) const1081 {1082         return [GJKIntersect](*this, sphere);1083 }1084 1085 bool [Frustum::Intersects](const [Capsule] &capsule) const1086 {1087         return [GJKIntersect](*this, capsule);1088 }1089 1090 bool [Frustum::Intersects](const [Frustum] &frustum) const1091 {1092         return [GJKIntersect](*this, frustum);1093 }1094 1095 bool [Frustum::Intersects](const [Polyhedron] &polyhedron) const1096 {1097         return this->[ToPolyhedron]().[Intersects](polyhedron);1098 }1099 1100 #if defined(MATH_TINYXML_INTEROP) && defined(MATH_CONTAINERLIB_SUPPORT)1101 1102 void Frustum::DeserializeFromXml(TiXmlElement *[e])1103 {1104         type = StrCaseEq(e->Attribute("orthographic"), "true") ? [OrthographicFrustum] : [PerspectiveFrustum];1105         pos = [POINT_VEC]([float3::FromString](e->Attribute("pos")));1106         front = [DIR_VEC]([float3::FromString](e->Attribute("front")));1107         up = [DIR_VEC]([float3::FromString](e->Attribute("up")));1108         e->QueryFloatAttribute("nearPlaneDistance", &nearPlaneDistance);1109         e->QueryFloatAttribute("farPlaneDistance", &farPlaneDistance);1110         e->QueryFloatAttribute("horizontalFov", &[horizontalFov]);1111         e->QueryFloatAttribute("verticalFov", &[verticalFov]);1112 }1113 1114 #endif1115 1116 #ifdef MATH_ENABLE_STL_SUPPORT1117 1118 std::string [FrustumTypeToString]([FrustumType] t)1119 {1120         if (t == [InvalidFrustum]) return "InvalidFrustum";1121         if (t == [OrthographicFrustum]) return "OrthographicFrustum";1122         if (t == [PerspectiveFrustum]) return "PerspectiveFrustum";1123         return "(invalid frustum type)";1124 }1125 1126 std::string [Frustum::ToString]() const1127 {1128         char str[256];1129         sprintf(str, "Frustum(%s pos:(%.2f, %.2f, %.2f) front:(%.2f, %.2f, %.2f), up:(%.2f, %.2f, %.2f), near: %.2f, far: %.2f, %s: %.2f, %s: %.2f)",1130                 [FrustumTypeToString](type).c_str(), pos.x, pos.y, pos.z, front.x, front.y, front.z,1131                 up.x, up.y, up.z, nearPlaneDistance, farPlaneDistance,1132                 type == [OrthographicFrustum] ? "ortho width:" : "hFov",1133                 [horizontalFov],1134                 type == [OrthographicFrustum] ? "ortho height:" : "vFov",1135                 [verticalFov]);1136         return str;1137 }1138 1139 std::ostream &[operator <<](std::ostream &o, const [Frustum] &frustum)1140 {1141         o << frustum.[ToString]();1142         return o;1143 }1144 1145 #endif1146 1147 [Frustum] [operator *](const [float3x3] &transform, const [Frustum] &frustum)1148 {1149         [Frustum] f(frustum);1150         f.Transform(transform);1151         return f;1152 }1153 1154 [Frustum] [operator *](const [float3x4] &transform, const [Frustum] &frustum)1155 {1156         [Frustum] f(frustum);1157         f.Transform(transform);1158         return f;1159 }1160 1161 [Frustum] [operator *](const [float4x4] &transform, const [Frustum] &frustum)1162 {1163         [Frustum] f(frustum);1164         f.Transform(transform);1165         return f;1166 }1167 1168 [Frustum] [operator *](const [Quat] &transform, const [Frustum] &frustum)1169 {1170         [Frustum] f(frustum);1171         f.Transform(transform);1172         return f;1173 }1174 1175 [MATH_END_NAMESPACE] Go back to previous page