using UnityEngine; using UnityEngine.Rendering; using UnityEngine.XR; namespace LuxWater { [RequireComponent(typeof(Camera))] [ExecuteInEditMode] public class LuxWater_ProjectorRenderer : MonoBehaviour { public enum BufferResolution { Full = 1, Half = 2, Quarter = 4, Eighth = 8 } [Space(8f)] public BufferResolution FoamBufferResolution = BufferResolution.Full; public BufferResolution NormalBufferResolution = BufferResolution.Full; [Space(2f)] [Header("Debug")] [Space(4f)] public bool DebugFoamBuffer; public bool DebugNormalBuffer; public bool DebugStats; private int drawnFoamProjectors; private int drawnNormalProjectors; private static CommandBuffer cb_Foam; private static CommandBuffer cb_Normals; private Camera cam; private Transform camTransform; private RenderTexture ProjectedFoam; private RenderTexture ProjectedNormals; private Texture2D defaultBump; private Bounds tempBounds; private int _LuxWater_FoamOverlayPID; private int _LuxWater_NormalOverlayPID; private Plane[] frustumPlanes = new Plane[6]; private Material DebugMat; private Material DebugNormalMat; private void OnEnable() { _LuxWater_FoamOverlayPID = Shader.PropertyToID("_LuxWater_FoamOverlay"); _LuxWater_NormalOverlayPID = Shader.PropertyToID("_LuxWater_NormalOverlay"); cb_Foam = new CommandBuffer(); cb_Foam.name = "Lux Water: Foam Overlay Buffer"; cb_Normals = new CommandBuffer(); cb_Normals.name = "Lux Water: Normal Overlay Buffer"; cam = GetComponent(); cam.AddCommandBuffer(CameraEvent.BeforeSkybox, cb_Foam); cam.AddCommandBuffer(CameraEvent.BeforeSkybox, cb_Normals); } private void OnDisable() { if (ProjectedFoam != null) { Object.DestroyImmediate(ProjectedFoam); } if (ProjectedNormals != null) { Object.DestroyImmediate(ProjectedNormals); } if (defaultBump != null) { Object.DestroyImmediate(defaultBump); } if (DebugMat != null) { Object.DestroyImmediate(DebugMat); } if (cb_Foam != null && cb_Foam.sizeInBytes > 0) { cb_Foam.Clear(); cb_Foam.Dispose(); } if (cb_Normals != null && cb_Normals.sizeInBytes > 0) { cb_Normals.Clear(); cb_Normals.Dispose(); } Shader.DisableKeyword("USINGWATERPROJECTORS"); } private void OnPreCull() { cam = GetComponent(); int count = LuxWater_Projector.FoamProjectors.Count; int count2 = LuxWater_Projector.NormalProjectors.Count; if (count + count2 == 0) { if (cb_Foam != null) { cb_Foam.Clear(); } if (cb_Normals != null) { cb_Normals.Clear(); } Shader.DisableKeyword("USINGWATERPROJECTORS"); return; } Shader.EnableKeyword("USINGWATERPROJECTORS"); Matrix4x4 projectionMatrix = cam.projectionMatrix; Matrix4x4 worldToCameraMatrix = cam.worldToCameraMatrix; Matrix4x4 worldToProjectMatrix = projectionMatrix * worldToCameraMatrix; int pixelWidth = cam.pixelWidth; int pixelHeight = cam.pixelHeight; GeomUtil.CalculateFrustumPlanes(frustumPlanes, worldToProjectMatrix); int num = Mathf.FloorToInt(pixelWidth / (int)FoamBufferResolution); int height = Mathf.FloorToInt(pixelHeight / (int)FoamBufferResolution); bool flag = false; TextureDimension dimension = TextureDimension.Tex2D; if (cam.stereoEnabled && XRSettings.stereoRenderingMode == XRSettings.StereoRenderingMode.SinglePassInstanced) { flag = true; dimension = TextureDimension.Tex2DArray; } if (!ProjectedFoam) { ProjectedFoam = new RenderTexture(num, height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear); ProjectedFoam.dimension = dimension; if (flag) { ProjectedFoam.volumeDepth = 2; } } else if (ProjectedFoam.width != num) { Object.DestroyImmediate(ProjectedFoam); ProjectedFoam = new RenderTexture(num, height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear); ProjectedFoam.dimension = dimension; if (flag) { ProjectedFoam.volumeDepth = 2; } } RenderTargetIdentifier renderTarget = ((!flag) ? new RenderTargetIdentifier(ProjectedFoam) : new RenderTargetIdentifier(ProjectedFoam, 0, CubemapFace.Unknown, -1)); cb_Foam.Clear(); cb_Foam.SetRenderTarget(renderTarget); cb_Foam.ClearRenderTarget(clearDepth: true, clearColor: true, new Color(0f, 0f, 0f, 0f), 1f); drawnFoamProjectors = 0; for (int i = 0; i < count; i++) { LuxWater_Projector luxWater_Projector = LuxWater_Projector.FoamProjectors[i]; tempBounds = luxWater_Projector.m_Rend.bounds; if (GeometryUtility.TestPlanesAABB(frustumPlanes, tempBounds)) { cb_Foam.DrawRenderer(luxWater_Projector.m_Rend, luxWater_Projector.m_Mat); drawnFoamProjectors++; } } Shader.SetGlobalTexture(_LuxWater_FoamOverlayPID, ProjectedFoam); num = Mathf.FloorToInt(pixelWidth / (int)NormalBufferResolution); height = Mathf.FloorToInt(pixelHeight / (int)NormalBufferResolution); if (!ProjectedNormals) { ProjectedNormals = new RenderTexture(num, height, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear); ProjectedNormals.name = "ProjectedNormals"; ProjectedNormals.dimension = dimension; if (flag) { ProjectedNormals.volumeDepth = 2; } } else if (ProjectedNormals.width != num) { Object.DestroyImmediate(ProjectedNormals); ProjectedNormals = new RenderTexture(num, height, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear); ProjectedNormals.name = "ProjectedNormals"; ProjectedNormals.dimension = dimension; if (flag) { ProjectedNormals.volumeDepth = 2; } } RenderTargetIdentifier renderTarget2 = ((!flag) ? new RenderTargetIdentifier(ProjectedNormals) : new RenderTargetIdentifier(ProjectedNormals, 0, CubemapFace.Unknown, -1)); cb_Normals.Clear(); cb_Normals.SetRenderTarget(renderTarget2); cb_Normals.ClearRenderTarget(clearDepth: true, clearColor: true, new Color(0f, 0f, 0f, 0f), 1f); drawnNormalProjectors = 0; for (int j = 0; j < count2; j++) { LuxWater_Projector luxWater_Projector2 = LuxWater_Projector.NormalProjectors[j]; tempBounds = luxWater_Projector2.m_Rend.bounds; if (GeometryUtility.TestPlanesAABB(frustumPlanes, tempBounds)) { cb_Normals.DrawRenderer(luxWater_Projector2.m_Rend, luxWater_Projector2.m_Mat); drawnNormalProjectors++; } } Shader.SetGlobalTexture(_LuxWater_NormalOverlayPID, ProjectedNormals); } private void OnDrawGizmos() { Camera component = GetComponent(); int num = 0; int num2 = (int)(component.aspect * 128f); if (DebugMat == null) { DebugMat = new Material(Shader.Find("Hidden/LuxWater_Debug")); } if (DebugNormalMat == null) { DebugNormalMat = new Material(Shader.Find("Hidden/LuxWater_DebugNormals")); } if (DebugFoamBuffer) { if (ProjectedFoam == null) { return; } GL.PushMatrix(); GL.LoadPixelMatrix(0f, Screen.width, Screen.height, 0f); Graphics.DrawTexture(new Rect(num, 0f, num2, 128f), ProjectedFoam, DebugMat); GL.PopMatrix(); num = num2; } if (DebugNormalBuffer && !(ProjectedNormals == null)) { GL.PushMatrix(); GL.LoadPixelMatrix(0f, Screen.width, Screen.height, 0f); Graphics.DrawTexture(new Rect(num, 0f, num2, 128f), ProjectedNormals, DebugNormalMat); GL.PopMatrix(); } } private void OnGUI() { if (DebugStats) { int count = LuxWater_Projector.FoamProjectors.Count; int count2 = LuxWater_Projector.NormalProjectors.Count; TextAnchor alignment = GUI.skin.label.alignment; GUI.skin.label.alignment = TextAnchor.MiddleLeft; GUI.Label(new Rect(10f, 0f, 300f, 40f), "Foam Projectors [Registered] " + count + " [Drawn] " + drawnFoamProjectors); GUI.Label(new Rect(10f, 18f, 300f, 40f), "Normal Projectors [Registered] " + count2 + " [Drawn] " + drawnNormalProjectors); GUI.skin.label.alignment = alignment; } } } }