using System; using System.Collections.Generic; using UltimateWater.Internal; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Serialization; namespace UltimateWater { [Serializable] public class WaterRenderer { [HideInInspector] [SerializeField] [FormerlySerializedAs("volumeFrontShader")] private Shader _VolumeFrontShader; [HideInInspector] [SerializeField] [FormerlySerializedAs("volumeFrontFastShader")] private Shader _VolumeFrontFastShader; [HideInInspector] [SerializeField] [FormerlySerializedAs("volumeBackShader")] private Shader _VolumeBackShader; [SerializeField] [FormerlySerializedAs("reflectionProbeAnchor")] private Transform _ReflectionProbeAnchor; [SerializeField] [FormerlySerializedAs("shadowCastingMode")] private ShadowCastingMode _ShadowCastingMode; [SerializeField] [FormerlySerializedAs("useSharedMask")] private bool _UseSharedMask = true; private Water _Water; private MaterialPropertyBlock _PropertyBlock; private RenderTexture _AdditiveMaskTexture; private RenderTexture _SubtractiveMaskTexture; private readonly List _Masks = new List(); public int MaskCount => _Masks.Count; public MaterialPropertyBlock PropertyBlock { get { if (_PropertyBlock == null) { return _PropertyBlock = new MaterialPropertyBlock(); } return _PropertyBlock; } } public Transform ReflectionProbeAnchor { get { return _ReflectionProbeAnchor; } set { _ReflectionProbeAnchor = value; } } public void AddMask(WaterSimpleMask mask) { mask.Renderer.enabled = false; int renderQueuePriority = mask.RenderQueuePriority; for (int num = _Masks.Count - 1; num >= 0; num--) { if (_Masks[num].RenderQueuePriority <= renderQueuePriority) { _Masks.Insert(num + 1, mask); return; } } _Masks.Insert(0, mask); } public void RemoveMask(WaterSimpleMask mask) { _Masks.Remove(mask); } public void RenderEffects(WaterCamera waterCamera) { Camera cameraComponent = waterCamera.CameraComponent; if (_Water.isActiveAndEnabled && (cameraComponent.cullingMask & (1 << _Water.gameObject.layer)) != 0 && (_Water.Volume.Boundless || !_Water.Volume.HasRenderableAdditiveVolumes || waterCamera.RenderVolumes)) { _Water.OnWaterRender(waterCamera); } } public void Render(Camera camera, WaterGeometryType geometryType, CommandBuffer commandBuffer = null, Shader shader = null) { if (!_Water.isActiveAndEnabled || (camera.cullingMask & (1 << _Water.gameObject.layer)) == 0) { return; } WaterCamera waterCamera = WaterCamera.GetWaterCamera(camera); if ((object)waterCamera == null || (!_Water.Volume.Boundless && _Water.Volume.HasRenderableAdditiveVolumes && !waterCamera.RenderVolumes)) { return; } if (_Water.ShaderSet.ReceiveShadows) { Vector2 min = new Vector2(0f, 0f); Vector2 max = new Vector2(1f, 1f); waterCamera.ReportShadowedWaterMinMaxRect(min, max); } if (!_UseSharedMask) { RenderMasks(camera, waterCamera, _PropertyBlock); } Matrix4x4 matrix; Mesh[] transformedMeshes = _Water.Geometry.GetTransformedMeshes(camera, out matrix, geometryType, volume: false, waterCamera.ForcedVertexCount); if (commandBuffer == null) { Camera camera2 = ((waterCamera.RenderMode != WaterRenderMode.DefaultQueue) ? waterCamera._WaterRenderCamera : camera); for (int i = 0; i < transformedMeshes.Length; i++) { Graphics.DrawMesh(transformedMeshes[i], matrix, _Water.Materials.SurfaceMaterial, _Water.gameObject.layer, camera2, 0, _PropertyBlock, _ShadowCastingMode, receiveShadows: false, (_ReflectionProbeAnchor != null) ? _ReflectionProbeAnchor : _Water.transform, useLightProbes: false); if (waterCamera.ContainingWater != null && waterCamera.Type == WaterCamera.CameraType.Normal) { Graphics.DrawMesh(transformedMeshes[i], matrix, _Water.Materials.SurfaceBackMaterial, _Water.gameObject.layer, camera2, 0, _PropertyBlock, _ShadowCastingMode, receiveShadows: false, (_ReflectionProbeAnchor != null) ? _ReflectionProbeAnchor : _Water.transform, useLightProbes: false); } } } else { Material variant = UtilityShaderVariants.Instance.GetVariant(shader, _Water.Materials.UsedKeywords); for (int j = 0; j < transformedMeshes.Length; j++) { commandBuffer.DrawMesh(transformedMeshes[j], matrix, variant, 0, 0, _PropertyBlock); } } } public void RenderVolumes(CommandBuffer commandBuffer, Shader shader, bool twoPass) { if (_Water.enabled) { Material variant = UtilityShaderVariants.Instance.GetVariant(shader, _Water.Materials.UsedKeywords); List volumesDirect = _Water.Volume.GetVolumesDirect(); RenderVolumes(commandBuffer, variant, volumesDirect, twoPass); List subtractiveVolumesDirect = _Water.Volume.GetSubtractiveVolumesDirect(); RenderVolumes(commandBuffer, variant, subtractiveVolumesDirect, twoPass); } } public void RenderMasks(CommandBuffer commandBuffer) { for (int num = _Masks.Count - 1; num >= 0; num--) { commandBuffer.DrawMesh(_Masks[num].GetComponent().sharedMesh, _Masks[num].transform.localToWorldMatrix, _Masks[num].Renderer.sharedMaterial, 0, 0); } } public void PostRender(WaterCamera waterCamera) { if (_Water != null) { _Water.OnWaterPostRender(waterCamera); } ReleaseTemporaryBuffers(); } public void OnSharedSubtractiveMaskRender(ref bool hasSubtractiveVolumes, ref bool hasAdditiveVolumes, ref bool hasFlatMasks) { if (!_Water.enabled) { return; } List volumesDirect = _Water.Volume.GetVolumesDirect(); int count = volumesDirect.Count; for (int i = 0; i < count; i++) { volumesDirect[i].DisableRenderers(); } List subtractiveVolumesDirect = _Water.Volume.GetSubtractiveVolumesDirect(); int count2 = subtractiveVolumesDirect.Count; if (_UseSharedMask) { for (int j = 0; j < count2; j++) { subtractiveVolumesDirect[j].EnableRenderers(forBorderRendering: false); } hasSubtractiveVolumes = hasSubtractiveVolumes || _Water.Volume.GetSubtractiveVolumesDirect().Count != 0; hasAdditiveVolumes = hasAdditiveVolumes || count != 0; hasFlatMasks = hasFlatMasks || _Masks.Count != 0; } else { for (int k = 0; k < count2; k++) { subtractiveVolumesDirect[k].DisableRenderers(); } } } public void OnSharedMaskAdditiveRender() { if (_Water.enabled && _UseSharedMask) { List volumesDirect = _Water.Volume.GetVolumesDirect(); int count = volumesDirect.Count; for (int i = 0; i < count; i++) { volumesDirect[i].EnableRenderers(forBorderRendering: false); } List subtractiveVolumesDirect = _Water.Volume.GetSubtractiveVolumesDirect(); int count2 = subtractiveVolumesDirect.Count; for (int j = 0; j < count2; j++) { subtractiveVolumesDirect[j].DisableRenderers(); } } } public void OnSharedMaskPostRender() { if (_Water.enabled) { List volumesDirect = _Water.Volume.GetVolumesDirect(); int count = volumesDirect.Count; for (int i = 0; i < count; i++) { volumesDirect[i].EnableRenderers(forBorderRendering: true); } List subtractiveVolumesDirect = _Water.Volume.GetSubtractiveVolumesDirect(); int count2 = subtractiveVolumesDirect.Count; for (int j = 0; j < count2; j++) { subtractiveVolumesDirect[j].EnableRenderers(forBorderRendering: true); } } } internal void Awake(Water water) { _Water = water; PropertyBlock.SetFloat("_RiverEnabled", 0f); } internal void OnValidate() { if (_VolumeFrontShader == null) { _VolumeFrontShader = Shader.Find("UltimateWater/Volumes/Front"); } if (_VolumeFrontFastShader == null) { _VolumeFrontFastShader = Shader.Find("UltimateWater/Volumes/Front Simple"); } if (_VolumeBackShader == null) { _VolumeBackShader = Shader.Find("UltimateWater/Volumes/Back"); } } private static void RenderVolumes(CommandBuffer commandBuffer, Material material, List boundingVolumes, bool twoPass) where T : WaterVolumeBase { for (int num = boundingVolumes.Count - 1; num >= 0; num--) { MeshRenderer[] volumeRenderers = boundingVolumes[num].VolumeRenderers; MeshFilter[] volumeFilters = boundingVolumes[num].VolumeFilters; if (volumeRenderers != null && volumeRenderers.Length != 0 && volumeRenderers[0].enabled) { if (!twoPass) { int shaderPass = ((material.passCount != 1) ? 1 : 0); for (int i = 0; i < volumeRenderers.Length; i++) { commandBuffer.DrawMesh(volumeFilters[i].sharedMesh, volumeRenderers[i].transform.localToWorldMatrix, material, 0, shaderPass); } } else { for (int j = 0; j < volumeRenderers.Length; j++) { Mesh sharedMesh = volumeFilters[j].sharedMesh; commandBuffer.DrawMesh(sharedMesh, volumeRenderers[j].transform.localToWorldMatrix, material, 0, 0); commandBuffer.DrawMesh(sharedMesh, volumeRenderers[j].transform.localToWorldMatrix, material, 0, 1); } } } } } private void ReleaseTemporaryBuffers() { if (_AdditiveMaskTexture != null) { RenderTexture.ReleaseTemporary(_AdditiveMaskTexture); _AdditiveMaskTexture = null; } if (_SubtractiveMaskTexture != null) { RenderTexture.ReleaseTemporary(_SubtractiveMaskTexture); _SubtractiveMaskTexture = null; } } private void RenderMasks(Camera camera, WaterCamera waterCamera, MaterialPropertyBlock propertyBlock) { List subtractiveVolumesDirect = _Water.Volume.GetSubtractiveVolumesDirect(); List volumesDirect = _Water.Volume.GetVolumesDirect(); if ((object)waterCamera == null || !waterCamera.RenderVolumes || (subtractiveVolumesDirect.Count == 0 && volumesDirect.Count == 0 && _Masks.Count == 0)) { ReleaseTemporaryBuffers(); return; } int waterTempLayer = WaterProjectSettings.Instance.WaterTempLayer; int waterCollidersLayer = WaterProjectSettings.Instance.WaterCollidersLayer; Camera effectsCamera = waterCamera.EffectsCamera; if (effectsCamera == null) { ReleaseTemporaryBuffers(); return; } bool hasSubtractiveVolumes = false; bool hasAdditiveVolumes = false; bool hasFlatMasks = false; OnSharedSubtractiveMaskRender(ref hasSubtractiveVolumes, ref hasAdditiveVolumes, ref hasFlatMasks); effectsCamera.CopyFrom(camera); effectsCamera.enabled = false; effectsCamera.GetComponent().enabled = false; effectsCamera.renderingPath = RenderingPath.Forward; effectsCamera.depthTextureMode = DepthTextureMode.None; effectsCamera.cullingMask = 1 << waterTempLayer; if (subtractiveVolumesDirect.Count != 0) { if (_SubtractiveMaskTexture == null) { _SubtractiveMaskTexture = RenderTexture.GetTemporary(camera.pixelWidth, camera.pixelHeight, 24, SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBFloat) ? RenderTextureFormat.ARGBFloat : RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear, 1); } Graphics.SetRenderTarget(_SubtractiveMaskTexture); int count = subtractiveVolumesDirect.Count; for (int i = 0; i < count; i++) { subtractiveVolumesDirect[i].SetLayer(waterTempLayer); } TemporaryRenderTexture temporary = RenderTexturesCache.GetTemporary(camera.pixelWidth, camera.pixelHeight, 24, SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBFloat) ? RenderTextureFormat.ARGBFloat : RenderTextureFormat.ARGBHalf, linear: true, uav: false); effectsCamera.clearFlags = CameraClearFlags.Color; effectsCamera.backgroundColor = new Color(0f, 0f, 0.5f, 0f); effectsCamera.targetTexture = temporary; effectsCamera.RenderWithShader(_VolumeFrontShader, "CustomType"); GL.Clear(clearDepth: true, clearColor: true, new Color(0f, 0f, 0f, 0f), 0f); Shader.SetGlobalTexture("_VolumesFrontDepth", (RenderTexture)temporary); effectsCamera.clearFlags = CameraClearFlags.Nothing; effectsCamera.targetTexture = _SubtractiveMaskTexture; effectsCamera.RenderWithShader(_VolumeBackShader, "CustomType"); temporary.Dispose(); for (int j = 0; j < count; j++) { subtractiveVolumesDirect[j].SetLayer(waterCollidersLayer); } propertyBlock.SetTexture(ShaderVariables.SubtractiveMask, _SubtractiveMaskTexture); } if (volumesDirect.Count != 0) { OnSharedMaskAdditiveRender(); if (_AdditiveMaskTexture == null) { _AdditiveMaskTexture = RenderTexture.GetTemporary(camera.pixelWidth, camera.pixelHeight, 16, SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBFloat) ? RenderTextureFormat.ARGBFloat : RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear, 1); } Graphics.SetRenderTarget(_AdditiveMaskTexture); GL.Clear(clearDepth: true, clearColor: true, new Color(0f, 0f, 0f, 0f)); int count2 = volumesDirect.Count; for (int k = 0; k < count2; k++) { volumesDirect[k].SetLayer(waterTempLayer); volumesDirect[k].EnableRenderers(forBorderRendering: false); } effectsCamera.clearFlags = CameraClearFlags.Nothing; effectsCamera.targetTexture = _AdditiveMaskTexture; effectsCamera.RenderWithShader(waterCamera.IsInsideAdditiveVolume ? _VolumeFrontShader : _VolumeFrontFastShader, "CustomType"); effectsCamera.clearFlags = CameraClearFlags.Nothing; effectsCamera.targetTexture = _AdditiveMaskTexture; effectsCamera.RenderWithShader(_VolumeBackShader, "CustomType"); for (int l = 0; l < count2; l++) { volumesDirect[l].SetLayer(waterCollidersLayer); } propertyBlock.SetTexture(ShaderVariables.AdditiveMask, _AdditiveMaskTexture); } OnSharedMaskPostRender(); effectsCamera.targetTexture = null; } } }