using System.Collections.Generic; using UnityEngine; namespace AQUAS { public class AQUAS_ProjectedGrid : MonoBehaviour { public GameObject waterplane; private GameObject ContainerObj; public Transform[] children; private AQUAS_Caustics[] causticComponents; private Camera cam; private GameObject projectorObj; private Camera projector; private Vector3[] farFrustumCorners; private Vector3[] nearFrustumCorners; private Vector3[] pFarFrustumCorners; private Vector3[] pNearFrustumCorners; private Material[] materials; public float waterLevel; private List intersectionPoints; private Vector4 minMax; private void Start() { children = new Transform[waterplane.transform.childCount]; List list = new List(); for (int i = 0; i < waterplane.transform.childCount; i++) { children[i] = waterplane.transform.GetChild(i); if (waterplane.transform.GetChild(i).GetComponent() != null) { list.Add(waterplane.transform.GetChild(i).GetComponent()); } } Transform[] array = children; foreach (Transform transform in array) { if (transform.name == "Static Boundary") { transform.parent = null; } if (transform.GetComponent() != null) { transform.parent = null; } } causticComponents = list.ToArray(); cam = GetComponent(); materials = waterplane.GetComponent().sharedMaterials; nearFrustumCorners = new Vector3[4]; farFrustumCorners = new Vector3[4]; pFarFrustumCorners = new Vector3[4]; pNearFrustumCorners = new Vector3[4]; waterLevel = waterplane.transform.position.y; projectorObj = new GameObject("Projector Object (" + base.transform.name + ")"); projectorObj.hideFlags = HideFlags.HideAndDontSave; projector = projectorObj.AddComponent(); projector.CopyFrom(cam); projector.depth = cam.depth - 1f; projector.enabled = false; intersectionPoints = new List(); ContainerObj = waterplane.transform.parent.gameObject; if (GetComponent() != null) { GetComponent().waterLevel = waterLevel; array = children; foreach (Transform transform2 in array) { if (transform2.name == "Static Boundary" && GetComponent() != null) { GetComponent().dynamicBoundary = transform2.gameObject; } } } if (!(GetComponent() != null)) { return; } GetComponent().waterLevel = waterLevel; array = children; foreach (Transform transform3 in array) { if (transform3.name == "Static Boundary") { GetComponent().dynamicBoundary = transform3.gameObject; } } } private void Update() { if (!projectorObj) { Start(); } Vector3 vector = cam.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, -1f)); projector.transform.position = new Vector3(vector.x, Mathf.Max(waterLevel + Mathf.Abs(waterLevel - cam.transform.position.y), waterLevel + 3f), vector.z); AQUAS_Caustics[] array = causticComponents; foreach (AQUAS_Caustics obj in array) { obj.waterLevel = waterLevel; obj.overrideWaterLevel = true; } cam.CalculateFrustumCorners(new Rect(0f, 0f, 1f, 1f), cam.farClipPlane, Camera.MonoOrStereoscopicEye.Mono, farFrustumCorners); cam.CalculateFrustumCorners(new Rect(0f, 0f, 1f, 1f), cam.nearClipPlane, Camera.MonoOrStereoscopicEye.Mono, nearFrustumCorners); projector.CalculateFrustumCorners(new Rect(0f, 0f, 1f, 1f), projector.farClipPlane, Camera.MonoOrStereoscopicEye.Mono, pFarFrustumCorners); projector.CalculateFrustumCorners(new Rect(0f, 0f, 1f, 1f), projector.nearClipPlane, Camera.MonoOrStereoscopicEye.Mono, pNearFrustumCorners); for (int j = 0; j < 4; j++) { farFrustumCorners[j] = base.transform.TransformPoint(farFrustumCorners[j]); nearFrustumCorners[j] = base.transform.TransformPoint(nearFrustumCorners[j]); pFarFrustumCorners[j] = projectorObj.transform.TransformPoint(pFarFrustumCorners[j]); pNearFrustumCorners[j] = projectorObj.transform.TransformPoint(pNearFrustumCorners[j]); } intersectionPoints.Clear(); GetAllIntersectionPoints(waterLevel); GetAllIntersectionPoints(waterLevel + 1f); GetAllIntersectionPoints(waterLevel - 1f); projector.aspect = cam.aspect; projector.fieldOfView = cam.fieldOfView; projector.transform.LookAt(AimProjector()); } private void OnPreCull() { Transform[] array = children; foreach (Transform transform in array) { if (!(transform == null)) { if (transform.name == "PrimaryCausticsProjector" || transform.name == "SecondaryCausticsProjector") { transform.position = new Vector3(base.transform.position.x, waterLevel, base.transform.position.z); transform.eulerAngles = new Vector3(90f, 0f, 0f); } else { transform.position = new Vector3(base.transform.position.x, waterLevel, base.transform.position.z); transform.eulerAngles = new Vector3(0f, 0f, 0f); transform.localScale = new Vector3(cam.farClipPlane / 2f, cam.farClipPlane / 2f, cam.farClipPlane / 2f); } } } PositionPlane(); minMax = GetBordersInViewport(); float num = Vector3.Distance(pNearFrustumCorners[0], pNearFrustumCorners[3]); float num2 = Vector3.Distance(pNearFrustumCorners[0], pNearFrustumCorners[1]); Material[] array2 = materials; foreach (Material material in array2) { material.SetVector("_ObjectScale", new Vector2(num / projector.nearClipPlane, num2 / projector.nearClipPlane)); material.SetVector("_RangeVector", minMax); material.SetFloat("_waterLevel", waterLevel); material.SetFloat("_ProjectGrid", 1f); if (material.HasProperty("_PhysicalNormalStrength")) { material.SetFloat("_PhysicalNormalStrength", 1f); } } } private void OnPostRender() { waterplane.transform.parent = ContainerObj.transform; } private void PositionPlane() { waterplane.transform.position = projector.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, projector.nearClipPlane)); waterplane.transform.eulerAngles = new Vector3(projector.transform.eulerAngles.x - 90f, projector.transform.eulerAngles.y, projector.transform.eulerAngles.z); waterplane.transform.parent = projectorObj.transform; } private void GetAllIntersectionPoints(float level) { Vector3 planeOrigin = new Vector3(0f, level, 0f); for (int i = 0; i < 4; i++) { int num = ((i != 3) ? (i + 1) : 0); if (LinePlaneIntersection(nearFrustumCorners[i], nearFrustumCorners[num], planeOrigin)) { intersectionPoints.Add(GetIntersectionPoint(nearFrustumCorners[i], nearFrustumCorners[num], planeOrigin)); } if (LinePlaneIntersection(farFrustumCorners[i], farFrustumCorners[num], planeOrigin)) { intersectionPoints.Add(GetIntersectionPoint(farFrustumCorners[i], farFrustumCorners[num], planeOrigin)); } if (LinePlaneIntersection(nearFrustumCorners[i], farFrustumCorners[i], planeOrigin)) { intersectionPoints.Add(GetIntersectionPoint(nearFrustumCorners[i], farFrustumCorners[i], planeOrigin)); } } } private bool LinePlaneIntersection(Vector3 startPoint, Vector3 targetPoint, Vector3 planeOrigin) { Vector3 up = Vector3.up; float num = Vector3.Dot(up, startPoint - planeOrigin); float num2 = Vector3.Dot(up, targetPoint - planeOrigin); if (num * num2 <= 0f) { return true; } return false; } private Vector3 GetIntersectionPoint(Vector3 startPoint, Vector3 targetPoint, Vector3 planeOrigin) { Vector3 up = Vector3.up; float num = Vector3.Dot(up, targetPoint - planeOrigin); Vector3 vector = (targetPoint - startPoint) / Vector3.Magnitude(targetPoint - startPoint); float num2 = Vector3.Dot(up, vector); return targetPoint - vector * (num / num2); } private Vector3 AimProjector() { Vector3 zero = Vector3.zero; if (LinePlaneIntersection(cam.transform.position, cam.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, cam.farClipPlane)), new Vector3(0f, waterLevel, 0f))) { Vector3 vector = cam.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, cam.farClipPlane)); if (cam.transform.position.y > waterLevel) { Vector3 startPoint = new Vector3(cam.transform.position.x, Mathf.Max(cam.transform.position.y, waterLevel + 3f), cam.transform.position.z); zero = GetIntersectionPoint(startPoint, cam.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, cam.farClipPlane)), new Vector3(0f, waterLevel, 0f)); } else if (cam.transform.position.y < waterLevel) { Vector3 startPoint = new Vector3(cam.transform.position.x, Mathf.Min(cam.transform.position.y, waterLevel - 3f), cam.transform.position.z); zero = GetIntersectionPoint(startPoint, cam.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, cam.farClipPlane)), new Vector3(0f, waterLevel, 0f)); } else { vector = cam.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, cam.farClipPlane)); zero = new Vector3(vector.x, waterLevel, vector.z); } } else { Vector3 vector2 = cam.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, cam.farClipPlane)); zero = new Vector3(vector2.x, 0f - Mathf.Abs(vector2.y), vector2.z); } return zero; } private Vector4 GetBordersInViewport() { float num = 1f; float num2 = 0f; float num3 = 1f; float num4 = 0f; for (int i = 0; i < intersectionPoints.Count; i++) { if (projector.WorldToViewportPoint(intersectionPoints[i]).x < num) { num = projector.WorldToViewportPoint(intersectionPoints[i]).x; } } for (int j = 0; j < intersectionPoints.Count; j++) { if (projector.WorldToViewportPoint(intersectionPoints[j]).x > num2) { num2 = projector.WorldToViewportPoint(intersectionPoints[j]).x; } } for (int k = 0; k < intersectionPoints.Count; k++) { if (projector.WorldToViewportPoint(intersectionPoints[k]).y < num3) { num3 = projector.WorldToViewportPoint(intersectionPoints[k]).y; } } for (int l = 0; l < intersectionPoints.Count; l++) { if (projector.WorldToViewportPoint(intersectionPoints[l]).y > num4) { num4 = projector.WorldToViewportPoint(intersectionPoints[l]).y; } } return new Vector4((num - 0.5f) * 1.1f, num3 - 0.5f, (num2 - 0.5f) * 1.1f, num4 - 0.5f); } } }