419 lines
14 KiB
C#
419 lines
14 KiB
C#
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)
|
|
{
|
|
return type switch
|
|
{
|
|
SpectrumType.Height => _HeightSpectrum,
|
|
SpectrumType.Normal => _NormalSpectrum,
|
|
SpectrumType.Displacement => _DisplacementSpectrum,
|
|
SpectrumType.RawDirectional => _DirectionalSpectrum,
|
|
SpectrumType.RawOmnidirectional => _OmnidirectionalSpectrum,
|
|
_ => 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;
|
|
if (!_SpectraDataCache.TryGetValue(spectrum, out var 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;
|
|
if (!_SpectraDataCache.TryGetValue(spectrum2, out var 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.RGFloat : RenderTextureFormat.RGHalf, RenderTextureReadWrite.Linear)
|
|
{
|
|
name = "[UWS] SpectrumResolver - Water Height Spectrum",
|
|
hideFlags = HideFlags.DontSave,
|
|
filterMode = FilterMode.Point
|
|
};
|
|
_NormalSpectrum = new RenderTexture(num, num, 0, finalHighPrecision ? RenderTextureFormat.ARGBFloat : RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear)
|
|
{
|
|
name = "[UWS] SpectrumResolver - Water Normals Spectrum",
|
|
hideFlags = HideFlags.DontSave,
|
|
filterMode = FilterMode.Point
|
|
};
|
|
_DisplacementSpectrum = new RenderTexture(num, num, 0, finalHighPrecision ? RenderTextureFormat.ARGBFloat : RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear)
|
|
{
|
|
name = "[UWS] SpectrumResolver - Water Displacement Spectrum",
|
|
hideFlags = HideFlags.DontSave,
|
|
filterMode = FilterMode.Point
|
|
};
|
|
_DirectionalSpectrum = new RenderTexture(num, num, 0, finalHighPrecision ? RenderTextureFormat.RGFloat : RenderTextureFormat.RGHalf, 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.RGBAFloat : TextureFormat.RGBAHalf, mipChain: false, linear: 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(updateMipmaps: false, makeNoLongerReadable: 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
|
|
{
|
|
name = "[PW Water] Spectrum Downsampling 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);
|
|
mesh.vertices = vertices;
|
|
mesh.normals = array;
|
|
mesh.uv = array2;
|
|
mesh.SetIndices(array3, MeshTopology.Quads, 0);
|
|
return mesh;
|
|
}
|
|
}
|
|
}
|