using UnityEngine; namespace AwesomeTechnologies.Utility { public class ShadowUtility { /// /// Check for shadow visibility, send minimum terrain height in worldspace as planeOrigin /// /// /// /// /// /// public static bool IsShadowVisible(Bounds objectBounds, Vector3 lightDirection, Vector3 planeOrigin, Plane[] frustumPlanes) { bool hitPlane; Bounds shadowBounds = GetShadowBounds(objectBounds, lightDirection, planeOrigin, out hitPlane); //return hitPlane && GeometryUtility.TestPlanesAABB(frustumPlanes, shadowBounds); return hitPlane && BoundsIntersectsFrustum(frustumPlanes, shadowBounds); } /// /// Test for bounds visible in frustum /// /// /// /// public static bool BoundsIntersectsFrustum(Plane[] planes, Bounds bounds) { var center = bounds.center; var extents = bounds.extents; for (int i = 0; i <= planes.Length -1; i++) { Vector3 planeNormal = planes[i].normal; float planeDistance = planes[i].distance; Vector3 abs = new Vector3(Mathf.Abs(planeNormal.x), Mathf.Abs(planeNormal.y), Mathf.Abs(planeNormal.z)); float r = extents.x * abs.x + extents.y * abs.y + extents.z * abs.z; float s = planeNormal.x * center.x + planeNormal.y * center.y + planeNormal.z * center.z; if (s + r < -planeDistance) { return false; } } return true; } /// /// Get the projected bounds of the shadow of an object /// /// /// /// /// /// public static Bounds GetShadowBounds(Bounds objectBounds, Vector3 lightDirection, Vector3 planeOrigin, out bool hitPlane) { Ray p0 = new Ray(new Vector3(objectBounds.min.x, objectBounds.max.y, objectBounds.min.z), lightDirection); Ray p1 = new Ray(new Vector3(objectBounds.min.x, objectBounds.max.y, objectBounds.max.z), lightDirection); Ray p2 = new Ray(new Vector3(objectBounds.max.x, objectBounds.max.y, objectBounds.min.z), lightDirection); Ray p3 = new Ray(objectBounds.max, lightDirection); Vector3 hitPoint; hitPlane = false; if (IntersectPlane(p0, planeOrigin, out hitPoint)) { objectBounds.Encapsulate(hitPoint); hitPlane = true; } if (IntersectPlane(p1, planeOrigin, out hitPoint)) { objectBounds.Encapsulate(hitPoint); hitPlane = true; } if (IntersectPlane(p2, planeOrigin, out hitPoint)) { objectBounds.Encapsulate(hitPoint); hitPlane = true; } if (IntersectPlane(p3, planeOrigin, out hitPoint)) { objectBounds.Encapsulate(hitPoint); hitPlane = true; } return objectBounds; } public static bool IntersectPlane(Ray ray, Vector3 planeOrigin, out Vector3 hitPoint) { Vector3 planeNormal = -Vector3.up; float denominator = Vector3.Dot(ray.direction, planeNormal); if (denominator > 0.00001f) { float t = Vector3.Dot(planeOrigin - ray.origin, planeNormal) / denominator; hitPoint = ray.origin + ray.direction * t; return true; } hitPoint = Vector3.zero; return false; } } }