Files
Fishing2/Assets/KriptoFX/WaterSystem2/WaterResources/Scripts/FeaturesHD/Runtime/Ocean/OceanCausticPrePass.cs
2025-11-16 22:37:55 +08:00

179 lines
8.3 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
using static KWS.KWS_CoreUtils;
using static KWS.KWS_ShaderConstants;
namespace KWS
{
internal class OceanCausticPrePass : WaterPass
{
internal override string PassName => "Water.CausticPrePass";
private static Dictionary<int, Mesh> _causticMeshes = new Dictionary<int, Mesh>();
static Material _causticMaterial;
private CommandBuffer _cmd;
const float KWS_CAUSTIC_MULTIPLIER = 0.15f;
private static bool _lastDispersionUsing;
static Dictionary<WaterQualityLevelSettings.CausticTextureResolutionQualityEnum, int> _causticQualityToMeshQuality = new Dictionary<WaterQualityLevelSettings.CausticTextureResolutionQualityEnum, int>()
{
{WaterQualityLevelSettings.CausticTextureResolutionQualityEnum.Extreme, 512},
{WaterQualityLevelSettings.CausticTextureResolutionQualityEnum.Ultra, 384},
{WaterQualityLevelSettings.CausticTextureResolutionQualityEnum.High, 256},
{WaterQualityLevelSettings.CausticTextureResolutionQualityEnum.Medium, 192},
{WaterQualityLevelSettings.CausticTextureResolutionQualityEnum.Low, 128},
};
public OceanCausticPrePass()
{
WaterSystem.OnAnyWaterSettingsChanged += OnAnyWaterSettingsChanged;
}
static void InitializeTextures(int size, int cascades, bool useDispersion)
{
var format = useDispersion ? GraphicsFormat.R8G8B8A8_UNorm : GraphicsFormat.R8_UNorm;
WaterSharedResources.CausticRTArray = KWS_CoreUtils.RTHandles.Alloc(size, size, colorFormat: format, name: "_CausticRTArray", useMipMap: true, autoGenerateMips: false, slices: cascades, dimension:TextureDimension.Tex2DArray);
Shader.SetGlobalTexture(CausticID.KWS_CausticRTArray, WaterSharedResources.CausticRTArray);
KWS_CoreUtils.ClearRenderTexture(WaterSharedResources.CausticRTArray.rt, ClearFlag.Color, new Color(KWS_CAUSTIC_MULTIPLIER, KWS_CAUSTIC_MULTIPLIER, KWS_CAUSTIC_MULTIPLIER));
//this.WaterLog(WaterSharedResources.CausticRTArray);
}
void ReleaseTextures()
{
WaterSharedResources.CausticRTArray?.Release();
WaterSharedResources.CausticRTArray = null;
this.WaterLog(string.Empty, KW_Extensions.WaterLogMessageType.ReleaseRT);
}
public override void Release()
{
WaterSystem.OnAnyWaterSettingsChanged -= OnAnyWaterSettingsChanged;
ReleaseTextures();
KW_Extensions.SafeDestroy(_causticMaterial);
foreach (var causticMesh in _causticMeshes) KW_Extensions.SafeDestroy(causticMesh.Value);
_causticMeshes.Clear();
this.WaterLog(string.Empty, KW_Extensions.WaterLogMessageType.Release);
}
private void OnAnyWaterSettingsChanged(WaterSystem.WaterSettingsCategory changedTabs)
{
if (KWS_Ocean.Instance == false) return;
var useCausticEffect = WaterQualityLevelSettings.ResolveQualityOverride(WaterSystem.Instance.CausticEffect, WaterSystem.QualitySettings.UseCausticEffect);
if(!useCausticEffect) return;
if (changedTabs.HasTab(WaterSystem.WaterSettingsCategory.Caustic))
{
var size = (int)WaterSystem.QualitySettings.OceanCausticTextureResolutionQuality;
var cascades = Mathf.Min(2, KWS_Ocean.Instance.FftWavesCascades);
var useCausticDispersion = WaterSystem.QualitySettings.UseOceanCausticDispersion;
if (WaterSharedResources.CausticRTArray == null
|| WaterSharedResources.CausticRTArray.rt.width != size
|| WaterSharedResources.CausticRTArray.rt.volumeDepth != cascades
||_lastDispersionUsing != useCausticDispersion)
{
_lastDispersionUsing = useCausticDispersion;
ReleaseTextures();
InitializeTextures(size, cascades, useCausticDispersion);
}
}
}
public override void ExecutePerFrame(HashSet<Camera> cameras, CustomFixedUpdates fixedUpdates)
{
if (KWS_Ocean.Instance == false) return;
if (fixedUpdates.TimeScaledFramesCount_60fps == 0) return;
var useCausticEffect = WaterQualityLevelSettings.ResolveQualityOverride(WaterSystem.Instance.CausticEffect, WaterSystem.QualitySettings.UseCausticEffect);
if(useCausticEffect == false) return;
if (_cmd == null) _cmd = new CommandBuffer() { name = PassName };
_cmd.Clear();
var size = (int)WaterSystem.QualitySettings.OceanCausticTextureResolutionQuality;
var cascades = Mathf.Min(2, KWS_Ocean.Instance.FftWavesCascades);
var useCausticDispersion = WaterSystem.QualitySettings.UseOceanCausticDispersion;
if (WaterSharedResources.CausticRTArray == null) InitializeTextures(size, cascades, useCausticDispersion);
if(_causticMaterial == null) _causticMaterial = KWS_CoreUtils.CreateMaterial(ShaderNames.CausticComputeShaderName);
ComputeCaustic();
if (WaterSharedResources.CausticRTArray != null) _cmd.GenerateMips(WaterSharedResources.CausticRTArray);
Graphics.ExecuteCommandBuffer(_cmd);
}
void ComputeCaustic()
{
var maxCascades = Mathf.Min(KWS_Ocean.Instance.FftWavesCascades, 2);
var mesh = GetOrCreateCausticMesh(WaterSystem.QualitySettings.OceanCausticTextureResolutionQuality);
_cmd.SetGlobalFloat("KWS_CausticDispersionStrength", WaterSystem.Instance.OceanCausticDispersionStrength);
for (int idx = 0; idx < maxCascades; idx++)
{
CoreUtils.SetRenderTarget(_cmd, WaterSharedResources.CausticRTArray, ClearFlag.Color, Color.clear, depthSlice: idx);
_cmd.SetGlobalInteger("KWS_CausticCascadeIndex", idx);
_cmd.DrawMesh(mesh, Matrix4x4.identity, _causticMaterial, submeshIndex: 0, shaderPass: 0);
}
}
internal static RenderTexture BakeCaustic(RenderTexture fftSource, float displacementScale, int fftCascadeIndexToBake, int currentFftSlice)
{
if (KWS_Ocean.Instance == false) return null;
var causticTex = new RenderTexture(256, 256, 0, GraphicsFormat.R8G8B8A8_UNorm);
causticTex.useMipMap = true;
causticTex.antiAliasing = 8;
causticTex.Create();
var cmd = new CommandBuffer();
var mesh = GetOrCreateCausticMesh(WaterQualityLevelSettings.CausticTextureResolutionQualityEnum.Extreme);
cmd.SetKeyword("KWS_CAUSTIC_BAKE_MODE", true);
cmd.SetGlobalFloat("KWS_DispacementScale", displacementScale);
cmd.SetGlobalTexture("KWS_BakedDisplacementFft", fftSource);
cmd.SetGlobalInteger("KWS_CausticCascadeIndex", fftCascadeIndexToBake);
cmd.SetGlobalInteger("KWS_BakedDisplacementSliceIndex", currentFftSlice);
CoreUtils.SetRenderTarget(cmd, causticTex, ClearFlag.Color, Color.clear);
cmd.DrawMesh(mesh, Matrix4x4.identity, _causticMaterial, submeshIndex: 0, shaderPass: 0);
cmd.SetKeyword("KWS_CAUSTIC_BAKE_MODE", false);
Graphics.ExecuteCommandBuffer(cmd);
return causticTex;
}
static Mesh GetOrCreateCausticMesh(WaterQualityLevelSettings.CausticTextureResolutionQualityEnum quality)
{
if (!_causticQualityToMeshQuality.TryGetValue(quality, out var size)) size = 256;
//var size = _causticQualityToMeshQuality[quality];
if (!_causticMeshes.ContainsKey(size))
{
_causticMeshes.Add(size, MeshUtils.CreatePlaneMesh(size, 1.25f));
}
return _causticMeshes[size];
}
}
}