44namespace FixedMathSharp ;
55
66/// <summary>
7- /// Represents a viewing frustum extracted from a combined view-projection matrix .
7+ /// Represents a frustum bounded by six clipping planes .
88/// </summary>
99public sealed class BoundingFrustum : IEquatable < BoundingFrustum >
1010{
@@ -24,7 +24,7 @@ public sealed class BoundingFrustum : IEquatable<BoundingFrustum>
2424
2525 #region Fields
2626
27- private Fixed4x4 _matrix ;
27+ private Fixed4x4 ? _matrix ;
2828 private readonly Vector3d [ ] _corners ;
2929 private readonly FixedPlane [ ] _planes ;
3030
@@ -46,27 +46,65 @@ public BoundingFrustum(Fixed4x4 matrix)
4646 {
4747 _corners = new Vector3d [ CornerCount ] ;
4848 _planes = new FixedPlane [ PlaneCount ] ;
49- Matrix = matrix ;
49+ SetMatrix ( matrix ) ;
50+ }
51+
52+ /// <summary>
53+ /// Initializes a new frustum from six clipping planes.
54+ /// </summary>
55+ public BoundingFrustum (
56+ FixedPlane near ,
57+ FixedPlane far ,
58+ FixedPlane left ,
59+ FixedPlane right ,
60+ FixedPlane top ,
61+ FixedPlane bottom )
62+ {
63+ _corners = new Vector3d [ CornerCount ] ;
64+ _planes = new FixedPlane [ PlaneCount ] ;
65+ SetPlanes ( near , far , left , right , top , bottom ) ;
66+ }
67+
68+ /// <summary>
69+ /// Initializes a new frustum from six clipping planes in near, far, left, right, top, bottom order.
70+ /// </summary>
71+ public BoundingFrustum ( FixedPlane [ ] planes )
72+ {
73+ if ( planes == null )
74+ throw new ArgumentNullException ( nameof ( planes ) ) ;
75+
76+ if ( planes . Length != PlaneCount )
77+ throw new ArgumentException ( $ "A frustum must be defined by exactly { PlaneCount } planes.", nameof ( planes ) ) ;
78+
79+ _corners = new Vector3d [ CornerCount ] ;
80+ _planes = new FixedPlane [ PlaneCount ] ;
81+ SetPlanes ( planes ) ;
5082 }
5183
5284 #endregion
5385
5486 #region Properties
5587
5688 /// <summary>
57- /// Gets or sets the matrix used to define this frustum.
89+ /// Gets a value indicating whether this frustum was created from a matrix source.
90+ /// </summary>
91+ public bool HasMatrix
92+ {
93+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
94+ get => _matrix . HasValue ;
95+ }
96+
97+ /// <summary>
98+ /// Gets or sets the matrix source used to define this frustum.
5899 /// </summary>
100+ /// <exception cref="InvalidOperationException">
101+ /// Thrown when reading the matrix from a frustum that was created from planes.
102+ /// </exception>
59103 public Fixed4x4 Matrix
60104 {
61105 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
62- get => _matrix ;
63- set
64- {
65- _matrix = value ;
66- CreatePlanes ( ) ;
67- CreateCorners ( ) ;
68- UpdateBounds ( ) ;
69- }
106+ get => _matrix ?? throw new InvalidOperationException ( "This frustum was not created from a matrix." ) ;
107+ set => SetMatrix ( value ) ;
70108 }
71109
72110 /// <summary>
@@ -380,14 +418,76 @@ public void GetCorners(Vector3d[] corners)
380418 Array . Copy ( _corners , corners , CornerCount ) ;
381419 }
382420
383- private void CreatePlanes ( )
421+ /// <summary>
422+ /// Returns a copy of the frustum plane array in near, far, left, right, top, bottom order.
423+ /// </summary>
424+ public FixedPlane [ ] GetPlanes ( )
425+ {
426+ var planes = new FixedPlane [ PlaneCount ] ;
427+ Array . Copy ( _planes , planes , PlaneCount ) ;
428+ return planes ;
429+ }
430+
431+ /// <summary>
432+ /// Copies this frustum's planes into the specified array in near, far, left, right, top, bottom order.
433+ /// </summary>
434+ public void GetPlanes ( FixedPlane [ ] planes )
435+ {
436+ if ( planes == null )
437+ throw new ArgumentNullException ( nameof ( planes ) ) ;
438+
439+ if ( planes . Length < PlaneCount )
440+ throw new ArgumentOutOfRangeException ( nameof ( planes ) ) ;
441+
442+ Array . Copy ( _planes , planes , PlaneCount ) ;
443+ }
444+
445+ private void SetMatrix ( Fixed4x4 matrix )
446+ {
447+ _matrix = matrix ;
448+ CreatePlanes ( matrix ) ;
449+ CreateCorners ( ) ;
450+ UpdateBounds ( ) ;
451+ }
452+
453+ private void SetPlanes ( FixedPlane [ ] planes )
454+ {
455+ for ( int i = 0 ; i < PlaneCount ; i ++ )
456+ _planes [ i ] = FixedPlane . Normalize ( planes [ i ] ) ;
457+
458+ _matrix = null ;
459+ CreateCorners ( ) ;
460+ UpdateBounds ( ) ;
461+ }
462+
463+ private void SetPlanes (
464+ FixedPlane near ,
465+ FixedPlane far ,
466+ FixedPlane left ,
467+ FixedPlane right ,
468+ FixedPlane top ,
469+ FixedPlane bottom )
384470 {
385- _planes [ 0 ] = FixedPlane . Normalize ( new FixedPlane ( - _matrix . m02 , - _matrix . m12 , - _matrix . m22 , - _matrix . m32 ) ) ;
386- _planes [ 1 ] = FixedPlane . Normalize ( new FixedPlane ( _matrix . m02 - _matrix . m03 , _matrix . m12 - _matrix . m13 , _matrix . m22 - _matrix . m23 , _matrix . m32 - _matrix . m33 ) ) ;
387- _planes [ 2 ] = FixedPlane . Normalize ( new FixedPlane ( - _matrix . m03 - _matrix . m00 , - _matrix . m13 - _matrix . m10 , - _matrix . m23 - _matrix . m20 , - _matrix . m33 - _matrix . m30 ) ) ;
388- _planes [ 3 ] = FixedPlane . Normalize ( new FixedPlane ( _matrix . m00 - _matrix . m03 , _matrix . m10 - _matrix . m13 , _matrix . m20 - _matrix . m23 , _matrix . m30 - _matrix . m33 ) ) ;
389- _planes [ 4 ] = FixedPlane . Normalize ( new FixedPlane ( _matrix . m01 - _matrix . m03 , _matrix . m11 - _matrix . m13 , _matrix . m21 - _matrix . m23 , _matrix . m31 - _matrix . m33 ) ) ;
390- _planes [ 5 ] = FixedPlane . Normalize ( new FixedPlane ( - _matrix . m03 - _matrix . m01 , - _matrix . m13 - _matrix . m11 , - _matrix . m23 - _matrix . m21 , - _matrix . m33 - _matrix . m31 ) ) ;
471+ _planes [ 0 ] = FixedPlane . Normalize ( near ) ;
472+ _planes [ 1 ] = FixedPlane . Normalize ( far ) ;
473+ _planes [ 2 ] = FixedPlane . Normalize ( left ) ;
474+ _planes [ 3 ] = FixedPlane . Normalize ( right ) ;
475+ _planes [ 4 ] = FixedPlane . Normalize ( top ) ;
476+ _planes [ 5 ] = FixedPlane . Normalize ( bottom ) ;
477+
478+ _matrix = null ;
479+ CreateCorners ( ) ;
480+ UpdateBounds ( ) ;
481+ }
482+
483+ private void CreatePlanes ( Fixed4x4 matrix )
484+ {
485+ _planes [ 0 ] = FixedPlane . Normalize ( new FixedPlane ( - matrix . m02 , - matrix . m12 , - matrix . m22 , - matrix . m32 ) ) ;
486+ _planes [ 1 ] = FixedPlane . Normalize ( new FixedPlane ( matrix . m02 - matrix . m03 , matrix . m12 - matrix . m13 , matrix . m22 - matrix . m23 , matrix . m32 - matrix . m33 ) ) ;
487+ _planes [ 2 ] = FixedPlane . Normalize ( new FixedPlane ( - matrix . m03 - matrix . m00 , - matrix . m13 - matrix . m10 , - matrix . m23 - matrix . m20 , - matrix . m33 - matrix . m30 ) ) ;
488+ _planes [ 3 ] = FixedPlane . Normalize ( new FixedPlane ( matrix . m00 - matrix . m03 , matrix . m10 - matrix . m13 , matrix . m20 - matrix . m23 , matrix . m30 - matrix . m33 ) ) ;
489+ _planes [ 4 ] = FixedPlane . Normalize ( new FixedPlane ( matrix . m01 - matrix . m03 , matrix . m11 - matrix . m13 , matrix . m21 - matrix . m23 , matrix . m31 - matrix . m33 ) ) ;
490+ _planes [ 5 ] = FixedPlane . Normalize ( new FixedPlane ( - matrix . m03 - matrix . m01 , - matrix . m13 - matrix . m11 , - matrix . m23 - matrix . m21 , - matrix . m33 - matrix . m31 ) ) ;
391491 }
392492
393493 private void CreateCorners ( )
@@ -518,14 +618,26 @@ private static void Project(Vector3d axis, Vector3d[] corners, out Fixed64 min,
518618 /// <inheritdoc/>
519619 public bool Equals ( BoundingFrustum ? other )
520620 {
521- return other != null && _matrix . Equals ( other . _matrix ) ;
621+ if ( other == null )
622+ return false ;
623+
624+ for ( int i = 0 ; i < PlaneCount ; i ++ )
625+ {
626+ if ( _planes [ i ] != other . _planes [ i ] )
627+ return false ;
628+ }
629+
630+ return true ;
522631 }
523632
524633 /// <inheritdoc/>
525634 public override bool Equals ( object ? obj ) => obj is BoundingFrustum other && Equals ( other ) ;
526635
527636 /// <inheritdoc/>
528- public override int GetHashCode ( ) => _matrix . GetHashCode ( ) ;
637+ public override int GetHashCode ( )
638+ {
639+ return HashCode . Combine ( _planes [ 0 ] , _planes [ 1 ] , _planes [ 2 ] , _planes [ 3 ] , _planes [ 4 ] , _planes [ 5 ] ) ;
640+ }
529641
530642 #endregion
531643}
0 commit comments