using System; using UnityEngine; namespace UltimateWater.Internal { public class SpectrumResolver : SpectrumResolverCPU { public enum SpectrumType { Height = 0, Normal = 1, Displacement = 2, RawDirectional = 3, RawOmnidirectional = 4 } private Texture2D _TileSizeLookup; private Texture _OmnidirectionalSpectrum; private RenderTexture _TotalOmnidirectionalSpectrum; private RenderTexture _DirectionalSpectrum; private RenderTexture _HeightSpectrum; private RenderTexture _NormalSpectrum; private RenderTexture _DisplacementSpectrum; private RenderBuffer[] _RenderTargetsx2; private RenderBuffer[] _RenderTargetsx3; private bool _TileSizesLookupDirty = true; private bool _DirectionalSpectrumDirty = true; private Vector4 _TileSizes; private Mesh _SpectrumDownsamplingMesh; private readonly Material _AnimationMaterial; private readonly Water _Water; private readonly WindWaves _WindWaves; public Texture TileSizeLookup { get { ValidateTileSizeLookup(); return _TileSizeLookup; } } public float RenderTime { get; private set; } public SpectrumResolver(Water water, WindWaves windWaves, Shader spectrumShader) : base(water, windWaves, 4) { _Water = water; _WindWaves = windWaves; _AnimationMaterial = new Material(spectrumShader) { hideFlags = HideFlags.DontSave }; _AnimationMaterial.SetFloat(ShaderVariables.RenderTime, Time.time); if (windWaves.LoopDuration != 0f) { _AnimationMaterial.EnableKeyword("_LOOPING"); _AnimationMaterial.SetFloat("_LoopDuration", windWaves.LoopDuration); } } public Texture RenderHeightSpectrumAt(float time) { CheckResources(); RenderTexture rawDirectionalSpectrum = GetRawDirectionalSpectrum(); RenderTime = time; _AnimationMaterial.SetFloat(ShaderVariables.RenderTime, time); Graphics.Blit(rawDirectionalSpectrum, _HeightSpectrum, _AnimationMaterial, 0); return _HeightSpectrum; } public Texture RenderNormalsSpectrumAt(float time) { CheckResources(); RenderTexture rawDirectionalSpectrum = GetRawDirectionalSpectrum(); RenderTime = time; _AnimationMaterial.SetFloat(ShaderVariables.RenderTime, time); Graphics.Blit(rawDirectionalSpectrum, _NormalSpectrum, _AnimationMaterial, 1); return _NormalSpectrum; } public void RenderDisplacementsSpectraAt(float time, out Texture height, out Texture displacement) { CheckResources(); height = _HeightSpectrum; displacement = _DisplacementSpectrum; _RenderTargetsx2[0] = _HeightSpectrum.colorBuffer; _RenderTargetsx2[1] = _DisplacementSpectrum.colorBuffer; RenderTexture rawDirectionalSpectrum = GetRawDirectionalSpectrum(); RenderTime = time; _AnimationMaterial.SetFloat(ShaderVariables.RenderTime, time); Graphics.SetRenderTarget(_RenderTargetsx2, _HeightSpectrum.depthBuffer); Graphics.Blit(rawDirectionalSpectrum, _AnimationMaterial, 5); Graphics.SetRenderTarget(null); } public void RenderCompleteSpectraAt(float time, out Texture height, out Texture normal, out Texture displacement) { CheckResources(); height = _HeightSpectrum; normal = _NormalSpectrum; displacement = _DisplacementSpectrum; _RenderTargetsx3[0] = _HeightSpectrum.colorBuffer; _RenderTargetsx3[1] = _NormalSpectrum.colorBuffer; _RenderTargetsx3[2] = _DisplacementSpectrum.colorBuffer; RenderTexture rawDirectionalSpectrum = GetRawDirectionalSpectrum(); RenderTime = time; _AnimationMaterial.SetFloat(ShaderVariables.RenderTime, time); Graphics.SetRenderTarget(_RenderTargetsx3, _HeightSpectrum.depthBuffer); Graphics.Blit(rawDirectionalSpectrum, _AnimationMaterial, 2); Graphics.SetRenderTarget(null); } public Texture GetSpectrum(SpectrumType type) { switch (type) { case SpectrumType.Height: return _HeightSpectrum; case SpectrumType.Normal: return _NormalSpectrum; case SpectrumType.Displacement: return _DisplacementSpectrum; case SpectrumType.RawDirectional: return _DirectionalSpectrum; case SpectrumType.RawOmnidirectional: return _OmnidirectionalSpectrum; default: throw new InvalidOperationException(); } } public override void AddSpectrum(WaterWavesSpectrumDataBase spectrum) { base.AddSpectrum(spectrum); _DirectionalSpectrumDirty = true; } public override void RemoveSpectrum(WaterWavesSpectrumDataBase spectrum) { base.RemoveSpectrum(spectrum); _DirectionalSpectrumDirty = true; } public override void SetDirectionalSpectrumDirty() { base.SetDirectionalSpectrumDirty(); _DirectionalSpectrumDirty = true; } internal override void OnProfilesChanged() { base.OnProfilesChanged(); if (_TileSizes != _WindWaves.TileSizes) { _TileSizesLookupDirty = true; _TileSizes = _WindWaves.TileSizes; } RenderTotalOmnidirectionalSpectrum(); } private void RenderTotalOmnidirectionalSpectrum() { _AnimationMaterial.SetFloat("_Gravity", _Water.Gravity); _AnimationMaterial.SetVector("_TargetResolution", new Vector4(_WindWaves.FinalResolution, _WindWaves.FinalResolution, 0f, 0f)); Water.WeightedProfile[] profiles = _Water.ProfilesManager.Profiles; if (profiles.Length > 1) { RenderTexture totalOmnidirectionalSpectrum = GetTotalOmnidirectionalSpectrum(); totalOmnidirectionalSpectrum.Clear(Color.black); for (int i = 0; i < profiles.Length; i++) { Water.WeightedProfile weightedProfile = profiles[i]; if (!(weightedProfile.Weight <= 0.0001f)) { WaterWavesSpectrum spectrum = weightedProfile.Profile.Spectrum; WaterWavesSpectrumData value; if (!_SpectraDataCache.TryGetValue(spectrum, out value)) { value = GetSpectrumData(spectrum); } _AnimationMaterial.SetFloat("_Weight", value.Weight); Graphics.Blit(value.Texture, totalOmnidirectionalSpectrum, _AnimationMaterial, 4); } } _OmnidirectionalSpectrum = totalOmnidirectionalSpectrum; } else if (profiles.Length != 0) { WaterWavesSpectrum spectrum2 = profiles[0].Profile.Spectrum; WaterWavesSpectrumData value2; if (!_SpectraDataCache.TryGetValue(spectrum2, out value2)) { value2 = GetSpectrumData(spectrum2); } value2.Weight = 1f; _OmnidirectionalSpectrum = value2.Texture; } _Water.Renderer.PropertyBlock.SetFloat("_MaxDisplacement", base.MaxHorizontalDisplacement); } private void RenderDirectionalSpectrum() { if (_OmnidirectionalSpectrum == null) { RenderTotalOmnidirectionalSpectrum(); } ValidateTileSizeLookup(); _AnimationMaterial.SetFloat("_Directionality", 1f - _WindWaves.SpectrumDirectionality); _AnimationMaterial.SetVector("_WindDirection", base.WindDirection); _AnimationMaterial.SetTexture("_TileSizeLookup", _TileSizeLookup); Graphics.Blit(_OmnidirectionalSpectrum, _DirectionalSpectrum, _AnimationMaterial, 3); AddOverlayToDirectionalSpectrum(); _DirectionalSpectrumDirty = false; } private void AddOverlayToDirectionalSpectrum() { if (_SpectrumDownsamplingMesh == null) { _SpectrumDownsamplingMesh = CreateDownsamplingMesh(); } for (int num = _OverlayedSpectra.Count - 1; num >= 0; num--) { WaterWavesSpectrumDataBase waterWavesSpectrumDataBase = _OverlayedSpectra[num]; Texture2D texture = waterWavesSpectrumDataBase.Texture; _AnimationMaterial.SetFloat("_Weight", waterWavesSpectrumDataBase.Weight); _AnimationMaterial.SetVector("_WindDirection", waterWavesSpectrumDataBase.WindDirection); float weatherSystemRadius = waterWavesSpectrumDataBase.WeatherSystemRadius; _AnimationMaterial.SetVector("_WeatherSystemRadius", new Vector4(2f * weatherSystemRadius, weatherSystemRadius * weatherSystemRadius, 0f, 0f)); Vector2 weatherSystemOffset = waterWavesSpectrumDataBase.WeatherSystemOffset; _AnimationMaterial.SetVector("_WeatherSystemOffset", new Vector4(weatherSystemOffset.x, weatherSystemOffset.y, weatherSystemOffset.magnitude, 0f)); Graphics.Blit(texture, _DirectionalSpectrum, _AnimationMaterial, 6); } } internal RenderTexture GetRawDirectionalSpectrum() { if ((_DirectionalSpectrumDirty || !_DirectionalSpectrum.IsCreated()) && Application.isPlaying) { CheckResources(); RenderDirectionalSpectrum(); } return _DirectionalSpectrum; } private RenderTexture GetTotalOmnidirectionalSpectrum() { if (_TotalOmnidirectionalSpectrum == null) { int num = _WindWaves.FinalResolution << 1; _TotalOmnidirectionalSpectrum = new RenderTexture(num, num, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear) { name = "[UWS] SpectrumResolver - Total Omnidirectional Spectrum", hideFlags = HideFlags.DontSave, filterMode = FilterMode.Point, wrapMode = TextureWrapMode.Repeat }; } return _TotalOmnidirectionalSpectrum; } private void CheckResources() { if (_HeightSpectrum == null) { int num = _WindWaves.FinalResolution << 1; bool finalHighPrecision = _WindWaves.FinalHighPrecision; _HeightSpectrum = new RenderTexture(num, num, 0, (!finalHighPrecision) ? RenderTextureFormat.RGHalf : RenderTextureFormat.RGFloat, RenderTextureReadWrite.Linear) { name = "[UWS] SpectrumResolver - Water Height Spectrum", hideFlags = HideFlags.DontSave, filterMode = FilterMode.Point }; _NormalSpectrum = new RenderTexture(num, num, 0, (!finalHighPrecision) ? RenderTextureFormat.ARGBHalf : RenderTextureFormat.ARGBFloat, RenderTextureReadWrite.Linear) { name = "[UWS] SpectrumResolver - Water Normals Spectrum", hideFlags = HideFlags.DontSave, filterMode = FilterMode.Point }; _DisplacementSpectrum = new RenderTexture(num, num, 0, (!finalHighPrecision) ? RenderTextureFormat.ARGBHalf : RenderTextureFormat.ARGBFloat, RenderTextureReadWrite.Linear) { name = "[UWS] SpectrumResolver - Water Displacement Spectrum", hideFlags = HideFlags.DontSave, filterMode = FilterMode.Point }; _DirectionalSpectrum = new RenderTexture(num, num, 0, (!finalHighPrecision) ? RenderTextureFormat.RGHalf : RenderTextureFormat.RGFloat, RenderTextureReadWrite.Linear) { hideFlags = HideFlags.DontSave, filterMode = FilterMode.Point, wrapMode = TextureWrapMode.Clamp }; _RenderTargetsx2 = new RenderBuffer[2] { _HeightSpectrum.colorBuffer, _DisplacementSpectrum.colorBuffer }; _RenderTargetsx3 = new RenderBuffer[3] { _HeightSpectrum.colorBuffer, _NormalSpectrum.colorBuffer, _DisplacementSpectrum.colorBuffer }; } } internal override void OnMapsFormatChanged(bool resolution) { base.OnMapsFormatChanged(resolution); if (_TotalOmnidirectionalSpectrum != null) { UnityEngine.Object.Destroy(_TotalOmnidirectionalSpectrum); _TotalOmnidirectionalSpectrum = null; } if (_HeightSpectrum != null) { UnityEngine.Object.Destroy(_HeightSpectrum); _HeightSpectrum = null; } if (_NormalSpectrum != null) { UnityEngine.Object.Destroy(_NormalSpectrum); _NormalSpectrum = null; } if (_DisplacementSpectrum != null) { UnityEngine.Object.Destroy(_DisplacementSpectrum); _DisplacementSpectrum = null; } if (_DirectionalSpectrum != null) { UnityEngine.Object.Destroy(_DirectionalSpectrum); _DirectionalSpectrum = null; } if (_TileSizeLookup != null) { UnityEngine.Object.Destroy(_TileSizeLookup); _TileSizeLookup = null; _TileSizesLookupDirty = true; } _OmnidirectionalSpectrum = null; _RenderTargetsx2 = null; _RenderTargetsx3 = null; } private void ValidateTileSizeLookup() { if (_TileSizesLookupDirty) { if (_TileSizeLookup == null) { _TileSizeLookup = new Texture2D(2, 2, (!SystemInfo.SupportsTextureFormat(TextureFormat.RGBAFloat)) ? TextureFormat.RGBAHalf : TextureFormat.RGBAFloat, false, true) { hideFlags = HideFlags.DontSave, wrapMode = TextureWrapMode.Clamp, filterMode = FilterMode.Point }; } _TileSizeLookup.SetPixel(0, 0, new Color(0.5f, 0.5f, 1f / _TileSizes.x, 0f)); _TileSizeLookup.SetPixel(1, 0, new Color(1.5f, 0.5f, 1f / _TileSizes.y, 0f)); _TileSizeLookup.SetPixel(0, 1, new Color(0.5f, 1.5f, 1f / _TileSizes.z, 0f)); _TileSizeLookup.SetPixel(1, 1, new Color(1.5f, 1.5f, 1f / _TileSizes.w, 0f)); _TileSizeLookup.Apply(false, false); _TileSizesLookupDirty = false; } } private static void AddQuad(Vector3[] vertices, Vector3[] origins, Vector2[] uvs, int index, float xOffset, float yOffset, int originIndex) { originIndex += index; float num = xOffset * 2f - 1f; float num2 = yOffset * 2f - 1f; uvs[index] = new Vector2(xOffset, yOffset); vertices[index++] = new Vector3(num, num2, 0.1f); uvs[index] = new Vector2(xOffset, yOffset + 0.25f); vertices[index++] = new Vector3(num, num2 + 0.5f, 0.1f); uvs[index] = new Vector2(xOffset + 0.25f, yOffset + 0.25f); vertices[index++] = new Vector3(num + 0.5f, num2 + 0.5f, 0.1f); uvs[index] = new Vector2(xOffset + 0.25f, yOffset); vertices[index] = new Vector3(num + 0.5f, num2, 0.1f); origins[index--] = vertices[originIndex]; origins[index--] = vertices[originIndex]; origins[index--] = vertices[originIndex]; origins[index] = vertices[originIndex]; } private static void AddQuads(Vector3[] vertices, Vector3[] origins, Vector2[] uvs, int index, float xOffset, float yOffset) { AddQuad(vertices, origins, uvs, index, xOffset, yOffset, 0); AddQuad(vertices, origins, uvs, index + 4, xOffset + 0.25f, yOffset, 3); AddQuad(vertices, origins, uvs, index + 8, xOffset, yOffset + 0.25f, 1); AddQuad(vertices, origins, uvs, index + 12, xOffset + 0.25f, yOffset + 0.25f, 2); } private static Mesh CreateDownsamplingMesh() { Mesh mesh = new Mesh(); mesh.name = "[PW Water] Spectrum Downsampling Mesh"; Mesh mesh2 = mesh; Vector3[] vertices = new Vector3[64]; Vector3[] array = new Vector3[64]; Vector2[] array2 = new Vector2[64]; int[] array3 = new int[64]; for (int i = 0; i < array3.Length; i++) { array3[i] = i; } AddQuads(vertices, array, array2, 0, 0f, 0f); AddQuads(vertices, array, array2, 16, 0.5f, 0f); AddQuads(vertices, array, array2, 32, 0f, 0.5f); AddQuads(vertices, array, array2, 48, 0.5f, 0.5f); mesh2.vertices = vertices; mesh2.normals = array; mesh2.uv = array2; mesh2.SetIndices(array3, MeshTopology.Quads, 0); return mesh2; } } }