コード例 #1
0
        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();
        }