static Plane[] GetClipPlanesForDirectionalLightShadowGeneration( Camera camera, RenderLight light, float farClipDistance) { float shadowFarDistance = SceneManager.Instance.ShadowFarDistance; Frustum cameraFrustum = FrustumUtils.GetFrustumByCamera( camera, farClipDistance ); Vec3 cameraPosition = cameraFrustum.Origin; Vec3 farCenterPoint; { float distance = shadowFarDistance; //small border distance *= 1.05f; //not optimal distance *= MathFunctions.Sqrt( 2 ); farCenterPoint = cameraPosition + cameraFrustum.Axis.Item0 * distance; } Vec3 pyramidCenter = ( cameraPosition + farCenterPoint ) * .5f; Plane farPlane; { Vec3 normal = ( farCenterPoint - cameraPosition ).GetNormalize(); float distance = Vec3.Dot( normal, farCenterPoint ); farPlane = new Plane( normal, distance ); } Vec3[] farCorners = new Vec3[ 4 ]; { //4 - top-right far, 5 - top-left far, 6 - bottom-left far, 7 - bottom-right far. Vec3[] points = camera.GetWorldSpaceCorners(); for( int n = 0; n < 4; n++ ) { Ray ray = new Ray( cameraPosition, points[ n + 4 ] - cameraPosition ); float scale; farPlane.RayIntersection( ray, out scale ); farCorners[ n ] = ray.GetPointOnRay( scale ); } } Vec3[] pyramidPoints = new Vec3[ 5 ]; { pyramidPoints[ 0 ] = cameraPosition; for( int n = 0; n < 4; n++ ) pyramidPoints[ n + 1 ] = farCorners[ n ]; } Line[] pyramidEdges = new Line[ 8 ]; { for( int n = 0; n < 4; n++ ) { pyramidEdges[ n ] = new Line( cameraPosition, farCorners[ n ] ); pyramidEdges[ n + 4 ] = new Line( farCorners[ n ], farCorners[ ( n + 1 ) % 4 ] ); } } List<Plane> clipPlanes = new List<Plane>( 7 ); { Vec3 lightDirectionOffset = light.Direction * 10000.0f; //back planes { if( farPlane.GetSide( farCenterPoint - lightDirectionOffset ) == Plane.Side.Negative ) { clipPlanes.Add( farPlane ); } for( int n = 0; n < 4; n++ ) { Plane plane = Plane.FromPoints( cameraPosition, farCorners[ n ], farCorners[ ( n + 1 ) % 4 ] ); if( plane.GetSide( cameraPosition - lightDirectionOffset ) == Plane.Side.Negative ) { clipPlanes.Add( farPlane ); } } } //generate edge planes foreach( Line pyramidEdge in pyramidEdges ) { Vec3 p1 = pyramidEdge.Start; Vec3 p2 = pyramidEdge.End; Vec3 p3 = p1 - lightDirectionOffset; Plane plane; { plane = Plane.FromPoints( p1, p2, p3 ); if( plane.GetSide( pyramidCenter ) == Plane.Side.Positive ) plane = Plane.FromPoints( p2, p1, p3 ); } bool existsPyramidPointsOnBothSides = false; { Plane.Side side = Plane.Side.No; bool sideInitialized = false; foreach( Vec3 pyramidPoint in pyramidPoints ) { if( pyramidPoint.Equals( pyramidEdge.Start, .00001f ) ) continue; if( pyramidPoint.Equals( pyramidEdge.End, .00001f ) ) continue; Plane.Side s = plane.GetSide( pyramidPoint ); if( sideInitialized ) { if( side == Plane.Side.Negative && s == Plane.Side.Positive || side == Plane.Side.Positive && s == Plane.Side.Negative ) { existsPyramidPointsOnBothSides = true; break; } } else { side = s; sideInitialized = true; } } } if( existsPyramidPointsOnBothSides ) continue; clipPlanes.Add( plane ); } } return clipPlanes.ToArray(); }