升级6.4.升级水,升级天气
This commit is contained in:
@@ -1,19 +1,16 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Experimental.Rendering;
|
||||
using UnityEngine.Rendering;
|
||||
using WaveHarmonic.Crest.Internal;
|
||||
using WaveHarmonic.Crest.Utility;
|
||||
|
||||
#if !UNITY_2023_2_OR_NEWER
|
||||
using GraphicsFormatUsage = UnityEngine.Experimental.Rendering.FormatUsage;
|
||||
#endif
|
||||
|
||||
namespace WaveHarmonic.Crest
|
||||
{
|
||||
using Inputs = SortedList<int, ILodInput>;
|
||||
using Inputs = Utility.SortedList<int, ILodInput>;
|
||||
|
||||
/// <summary>
|
||||
/// Texture format preset.
|
||||
@@ -42,7 +39,7 @@ namespace WaveHarmonic.Crest
|
||||
/// Base class for data/behaviours created on each LOD.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public abstract partial class Lod
|
||||
public abstract partial class Lod : Versioned
|
||||
{
|
||||
[Tooltip("Whether the simulation is enabled.")]
|
||||
[@GenerateAPI(Getter.Custom, Setter.Custom)]
|
||||
@@ -50,14 +47,13 @@ namespace WaveHarmonic.Crest
|
||||
internal bool _Enabled;
|
||||
|
||||
[Tooltip("Whether to override the resolution.\n\nIf not enabled, then the simulation will use the resolution defined on the Water Renderer.")]
|
||||
[@Predicated(typeof(AnimatedWavesLod), inverted: true, hide: true)]
|
||||
[@Hide(typeof(AnimatedWavesLod))]
|
||||
[@GenerateAPI(Setter.Dirty)]
|
||||
[@InlineToggle(fix: true), SerializeField]
|
||||
[@InlineToggle, SerializeField]
|
||||
internal bool _OverrideResolution = true;
|
||||
|
||||
[Tooltip("The resolution of the simulation data.\n\nSet higher for sharper results at the cost of higher memory usage.")]
|
||||
[@Predicated(typeof(AnimatedWavesLod), inverted: true, hide: true)]
|
||||
[@Predicated(nameof(_OverrideResolution), hide: true)]
|
||||
[@Show(nameof(_OverrideResolution))]
|
||||
[@ShowComputedProperty(nameof(Resolution))]
|
||||
[@Delayed]
|
||||
[@GenerateAPI(Getter.Custom, Setter.Dirty)]
|
||||
@@ -72,25 +68,45 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
[Tooltip("The render texture format used for this simulation data.\n\nIt will be overriden if the format is incompatible with the platform.")]
|
||||
[@ShowComputedProperty(nameof(RequestedTextureFormat))]
|
||||
[@Predicated(nameof(_TextureFormatMode), inverted: true, nameof(LodTextureFormatMode.Manual), hide: true)]
|
||||
[@Show(nameof(_TextureFormatMode), nameof(LodTextureFormatMode.Manual))]
|
||||
[@GenerateAPI(Setter.Dirty)]
|
||||
[@DecoratedField, SerializeField]
|
||||
internal GraphicsFormat _TextureFormat;
|
||||
|
||||
[@Space(10)]
|
||||
|
||||
[Tooltip("Blurs the output.\n\nEnable if blurring is desired or intolerable artifacts are present.\nThe blur is optimized to only run on inner LODs and at lower scales.")]
|
||||
[@Hide(typeof(AnimatedWavesLod))]
|
||||
[@Hide(typeof(DynamicWavesLod))]
|
||||
[@GenerateAPI(Setter.Dirty)]
|
||||
[@DecoratedField]
|
||||
[SerializeField]
|
||||
private protected bool _Blur;
|
||||
|
||||
[Tooltip("Number of blur iterations.\n\nBlur iterations are optimized to only run maximum iterations on the inner LODs.")]
|
||||
[@Hide(typeof(AnimatedWavesLod))]
|
||||
[@Hide(typeof(DynamicWavesLod))]
|
||||
[@Enable(nameof(_Blur))]
|
||||
[@GenerateAPI]
|
||||
[@DecoratedField]
|
||||
[SerializeField]
|
||||
private protected int _BlurIterations = 1;
|
||||
|
||||
// NOTE: This MUST match the value in Constants.hlsl, as it
|
||||
// determines the size of the texture arrays in the shaders.
|
||||
internal const int k_MaximumSlices = 15;
|
||||
|
||||
// NOTE: these MUST match the values in Constants.hlsl
|
||||
// 64 recommended as a good common minimum: https://www.reddit.com/r/GraphicsProgramming/comments/aeyfkh/for_compute_shaders_is_there_an_ideal_numthreads/
|
||||
internal const int k_ThreadGroupSize = 8;
|
||||
internal const int k_ThreadGroupSizeX = k_ThreadGroupSize;
|
||||
internal const int k_ThreadGroupSizeY = k_ThreadGroupSize;
|
||||
|
||||
internal const string k_BlurField = nameof(_Blur);
|
||||
internal const string k_TextureFormatModeField = nameof(_TextureFormatMode);
|
||||
|
||||
internal static class ShaderIDs
|
||||
{
|
||||
public static readonly int s_LodIndex = Shader.PropertyToID("_Crest_LodIndex");
|
||||
public static readonly int s_LodChange = Shader.PropertyToID("_Crest_LodChange");
|
||||
public static readonly int s_TemporaryBlurLodTexture = Shader.PropertyToID("_Crest_TemporaryBlurLodTexture");
|
||||
}
|
||||
|
||||
// Used for creating shader property names etc.
|
||||
@@ -136,17 +152,10 @@ namespace WaveHarmonic.Crest
|
||||
}
|
||||
}
|
||||
|
||||
static readonly GraphicsFormatUsage s_GraphicsFormatUsage =
|
||||
// Ensures a non compressed format is returned.
|
||||
GraphicsFormatUsage.LoadStore |
|
||||
// All these textures are sampled at some point.
|
||||
GraphicsFormatUsage.Sample |
|
||||
// Always use linear filtering.
|
||||
GraphicsFormatUsage.Linear;
|
||||
private protected bool Persistent => BufferCount > 1;
|
||||
internal virtual bool SkipEndOfFrame => false;
|
||||
|
||||
private protected BufferedData<RenderTexture> _Targets;
|
||||
internal RenderTexture DataTexture => _Targets.Current;
|
||||
internal RenderTexture GetDataTexture(int frameDelta) => _Targets.Previous(frameDelta);
|
||||
internal RenderTexture DataTexture { get; private protected set; }
|
||||
|
||||
private protected Matrix4x4[] _ViewMatrices = new Matrix4x4[k_MaximumSlices];
|
||||
private protected Cascade[] _Cascades = new Cascade[k_MaximumSlices];
|
||||
@@ -161,7 +170,7 @@ namespace WaveHarmonic.Crest
|
||||
internal WaterRenderer _Water;
|
||||
internal WaterRenderer Water => _Water;
|
||||
|
||||
private protected int _TargetsToClear;
|
||||
private protected bool _TargetsToClear;
|
||||
|
||||
private protected readonly int _TextureShaderID;
|
||||
private protected readonly int _TextureSourceShaderID;
|
||||
@@ -184,8 +193,10 @@ namespace WaveHarmonic.Crest
|
||||
_TextureName = $"_Crest_{ID}Lod";
|
||||
}
|
||||
|
||||
private protected RenderTexture CreateLodDataTextures()
|
||||
private protected RenderTexture CreateLodDataTextures(string postfix = null)
|
||||
{
|
||||
postfix ??= string.Empty;
|
||||
|
||||
RenderTexture result = new(Resolution, Resolution, 0, CompatibleTextureFormat)
|
||||
{
|
||||
wrapMode = TextureWrapMode.Clamp,
|
||||
@@ -193,7 +204,7 @@ namespace WaveHarmonic.Crest
|
||||
filterMode = FilterMode.Bilinear,
|
||||
anisoLevel = 0,
|
||||
useMipMap = false,
|
||||
name = _TextureName,
|
||||
name = _TextureName + postfix,
|
||||
dimension = TextureDimension.Tex2DArray,
|
||||
volumeDepth = Slices,
|
||||
enableRandomWrite = NeedToReadWriteTextureData
|
||||
@@ -202,7 +213,7 @@ namespace WaveHarmonic.Crest
|
||||
return result;
|
||||
}
|
||||
|
||||
private protected void FlipBuffers()
|
||||
private protected void FlipBuffers(CommandBuffer commands)
|
||||
{
|
||||
if (_ReAllocateTexture)
|
||||
{
|
||||
@@ -214,11 +225,10 @@ namespace WaveHarmonic.Crest
|
||||
if (!UnityEditor.EditorApplication.isPaused || Time.deltaTime > 0)
|
||||
#endif
|
||||
{
|
||||
_Targets.Flip();
|
||||
_SamplingParameters.Flip();
|
||||
}
|
||||
|
||||
UpdateSamplingParameters();
|
||||
UpdateSamplingParameters(commands);
|
||||
}
|
||||
|
||||
private protected void Clear(RenderTexture target)
|
||||
@@ -226,29 +236,36 @@ namespace WaveHarmonic.Crest
|
||||
Helpers.ClearRenderTexture(target, ClearColor, depth: false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears persistent LOD data. Some simulations have persistent data which can linger for a little while after
|
||||
/// being disabled. This will manually clear that data.
|
||||
/// </summary>
|
||||
internal virtual void ClearLodData()
|
||||
{
|
||||
// Empty.
|
||||
}
|
||||
|
||||
private protected virtual bool AlwaysClear => false;
|
||||
|
||||
// Only works with input-only data (ie no simulation steps).
|
||||
internal virtual void BuildCommandBuffer(WaterRenderer water, CommandBuffer buffer)
|
||||
{
|
||||
FlipBuffers();
|
||||
FlipBuffers(buffer);
|
||||
|
||||
buffer.BeginSample(ID);
|
||||
|
||||
if (_TargetsToClear > 0 || AlwaysClear)
|
||||
if (_TargetsToClear || AlwaysClear)
|
||||
{
|
||||
// IMPORTANT:
|
||||
// We need both clears otherwise problems on PS5.
|
||||
// With only native clear, flow would clear to non black (ie constant flow).
|
||||
// With only custom clear, absorption/scattering inputs were not clearing.
|
||||
CoreUtils.SetRenderTarget(buffer, DataTexture, ClearFlag.Color, ClearColor);
|
||||
|
||||
_TargetsToClear--;
|
||||
// Custom clear because clear not working.
|
||||
if (Helpers.RequiresCustomClear && WaterResources.Instance.Compute._Clear != null)
|
||||
{
|
||||
var compute = WaterResources.Instance._ComputeLibrary._ClearCompute;
|
||||
var wrapper = new PropertyWrapperCompute(buffer, compute._Shader, compute._KernelClearTarget);
|
||||
compute.SetVariantForFormat(wrapper, CompatibleTextureFormat);
|
||||
wrapper.SetTexture(Crest.ShaderIDs.s_Target, DataTexture);
|
||||
wrapper.SetVector(Crest.ShaderIDs.s_ClearMask, Color.white);
|
||||
wrapper.SetVector(Crest.ShaderIDs.s_ClearColor, ClearColor);
|
||||
wrapper.Dispatch(Resolution / k_ThreadGroupSizeX, Resolution / k_ThreadGroupSizeY, Slices);
|
||||
}
|
||||
|
||||
_TargetsToClear = false;
|
||||
}
|
||||
|
||||
if (Inputs.Count > 0)
|
||||
@@ -256,9 +273,11 @@ namespace WaveHarmonic.Crest
|
||||
SubmitDraws(buffer, Inputs, DataTexture);
|
||||
|
||||
// Ensure all targets clear when there are no inputs.
|
||||
_TargetsToClear = _Targets.Size;
|
||||
_TargetsToClear = true;
|
||||
}
|
||||
|
||||
TryBlur(buffer);
|
||||
|
||||
if (RequiresClearBorder)
|
||||
{
|
||||
ClearBorder(buffer);
|
||||
@@ -354,14 +373,18 @@ namespace WaveHarmonic.Crest
|
||||
{
|
||||
var size = Resolution / 8;
|
||||
|
||||
var wrapper = new PropertyWrapperCompute(buffer, WaterResources.Instance.Compute._Clear, 1);
|
||||
var compute = WaterResources.Instance._ComputeLibrary._ClearCompute;
|
||||
|
||||
var wrapper = new PropertyWrapperCompute(buffer, compute._Shader, compute._KernelClearTargetBoundaryX);
|
||||
// Only need to be done once.
|
||||
compute.SetVariantForFormat(wrapper, DataTexture.graphicsFormat);
|
||||
wrapper.SetTexture(Crest.ShaderIDs.s_Target, DataTexture);
|
||||
wrapper.SetVector(Crest.ShaderIDs.s_ClearColor, ClearColor);
|
||||
wrapper.SetInteger(Crest.ShaderIDs.s_Resolution, Resolution);
|
||||
wrapper.SetInteger(Crest.ShaderIDs.s_TargetSlice, Slices - 1);
|
||||
wrapper.Dispatch(size, 1, 1);
|
||||
|
||||
wrapper = new PropertyWrapperCompute(buffer, WaterResources.Instance.Compute._Clear, 2);
|
||||
wrapper = new(buffer, compute._Shader, compute._KernelClearTargetBoundaryY);
|
||||
wrapper.SetTexture(Crest.ShaderIDs.s_Target, DataTexture);
|
||||
wrapper.SetVector(Crest.ShaderIDs.s_ClearColor, ClearColor);
|
||||
wrapper.SetInteger(Crest.ShaderIDs.s_Resolution, Resolution);
|
||||
@@ -369,7 +392,7 @@ namespace WaveHarmonic.Crest
|
||||
wrapper.Dispatch(1, size, 1);
|
||||
}
|
||||
|
||||
void UpdateSamplingParameters(bool initialize = false)
|
||||
void UpdateSamplingParameters(CommandBuffer commands, bool initialize = false)
|
||||
{
|
||||
var position = _Water.Position;
|
||||
var resolution = _Enabled ? Resolution : TextureArrayHelpers.k_SmallTextureSize;
|
||||
@@ -380,7 +403,7 @@ namespace WaveHarmonic.Crest
|
||||
for (var slice = 0; slice < levels; slice++)
|
||||
{
|
||||
// Find snap period.
|
||||
var texel = 2f * 2f * _Water._CascadeData.Current[slice].x / resolution;
|
||||
var texel = 2f * 2f * _Water.CascadeData.Current[slice].x / resolution;
|
||||
// Snap so that shape texels are stationary.
|
||||
var snapped = position - new Vector3(Mathf.Repeat(position.x, texel), 0, Mathf.Repeat(position.z, texel));
|
||||
|
||||
@@ -392,11 +415,20 @@ namespace WaveHarmonic.Crest
|
||||
_ViewMatrices[slice] = WaterRenderer.CalculateViewMatrixFromSnappedPositionRHS(snapped);
|
||||
}
|
||||
|
||||
if (initialize)
|
||||
if (!initialize)
|
||||
{
|
||||
Shader.SetGlobalVector(_SamplingParametersShaderID, new(levels, resolution, 1f / resolution, 0));
|
||||
commands.SetGlobalVector(_SamplingParametersShaderID, new(levels, resolution, 1f / resolution, 0));
|
||||
commands.SetGlobalVectorArray(_SamplingParametersCascadeShaderID, parameters);
|
||||
|
||||
if (BufferCount > 1)
|
||||
{
|
||||
commands.SetGlobalVectorArray(_SamplingParametersCascadeSourceShaderID, _SamplingParameters.Previous(1));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Shader.SetGlobalVector(_SamplingParametersShaderID, new(levels, resolution, 1f / resolution, 0));
|
||||
Shader.SetGlobalVectorArray(_SamplingParametersCascadeShaderID, parameters);
|
||||
|
||||
if (BufferCount > 1)
|
||||
@@ -468,7 +500,7 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
// The smallest wavelengths should repeat no more than twice across the smaller
|
||||
// spatial length. Unless we're in the last LOD - then this is the best we can do.
|
||||
var minimumWavelength = _Water.MaximumWavelength(index) / 2f;
|
||||
var minimumWavelength = _Water.MaximumWavelength(index, Resolution) / 2f;
|
||||
if (minimumWavelength < minimumSpatialLength / 2f && index < count - 1)
|
||||
{
|
||||
continue;
|
||||
@@ -480,6 +512,48 @@ namespace WaveHarmonic.Crest
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Blurs the output if enabled.
|
||||
private protected void TryBlur(CommandBuffer commands)
|
||||
{
|
||||
if (!_Blur || _Water.Scale >= 32)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var rt = DataTexture;
|
||||
|
||||
var compute = WaterResources.Instance._ComputeLibrary._BlurCompute;
|
||||
|
||||
var horizontal = new PropertyWrapperCompute(commands, compute._Shader, compute._KernelHorizontal);
|
||||
var vertical = new PropertyWrapperCompute(commands, compute._Shader, compute._KernelVertical);
|
||||
|
||||
var temporary = ShaderIDs.s_TemporaryBlurLodTexture;
|
||||
|
||||
commands.GetTemporaryRT(temporary, rt.descriptor);
|
||||
|
||||
// Applies to both.
|
||||
compute.SetVariantForFormat(horizontal, rt.graphicsFormat);
|
||||
horizontal.SetInteger(Crest.ShaderIDs.s_Resolution, rt.width);
|
||||
|
||||
horizontal.SetTexture(Crest.ShaderIDs.s_Source, rt);
|
||||
horizontal.SetTexture(Crest.ShaderIDs.s_Target, temporary);
|
||||
vertical.SetTexture(Crest.ShaderIDs.s_Source, temporary);
|
||||
vertical.SetTexture(Crest.ShaderIDs.s_Target, rt);
|
||||
|
||||
var x = rt.width / 8;
|
||||
var y = rt.height / 8;
|
||||
// Skip outer LODs.
|
||||
var z = Mathf.Min(rt.volumeDepth, 4);
|
||||
for (var i = 0; i < _BlurIterations; i++)
|
||||
{
|
||||
// Limit number of iterations for outer LODs.
|
||||
horizontal.Dispatch(x, y, Mathf.Max(z - i, 1));
|
||||
vertical.Dispatch(x, y, Mathf.Max(z - i, 1));
|
||||
}
|
||||
|
||||
commands.ReleaseTemporaryRT(temporary);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bind data needed to load or compute from this simulation.
|
||||
/// </summary>
|
||||
@@ -500,7 +574,7 @@ namespace WaveHarmonic.Crest
|
||||
// Validate textures.
|
||||
{
|
||||
// Find a compatible texture format.
|
||||
CompatibleTextureFormat = Helpers.GetCompatibleTextureFormat(RequestedTextureFormat, s_GraphicsFormatUsage, Name, NeedToReadWriteTextureData);
|
||||
CompatibleTextureFormat = Helpers.GetCompatibleTextureFormat(RequestedTextureFormat, Helpers.s_DataGraphicsFormatUsage, Name, NeedToReadWriteTextureData);
|
||||
|
||||
if (CompatibleTextureFormat == GraphicsFormat.None)
|
||||
{
|
||||
@@ -523,20 +597,15 @@ namespace WaveHarmonic.Crest
|
||||
// Bind/unbind data texture for all shaders.
|
||||
Shader.SetGlobalTexture(_TextureShaderID, enable && Enabled ? DataTexture : NullTexture);
|
||||
|
||||
if (BufferCount > 1)
|
||||
{
|
||||
Shader.SetGlobalTexture(_TextureSourceShaderID, enable && Enabled ? GetDataTexture(1) : NullTexture);
|
||||
}
|
||||
|
||||
if (_SamplingParameters == null || _SamplingParameters.Size != BufferCount)
|
||||
{
|
||||
_SamplingParameters = new(BufferCount, () => new Vector4[k_MaximumSlices]);
|
||||
}
|
||||
|
||||
// For safety. Disable to see if we are sampling outside of LOD chain.
|
||||
_SamplingParameters.RunLambda(x => System.Array.Fill(x, Vector4.zero));
|
||||
_SamplingParameters.RunLambda(x => System.Array.Fill(x, new(0, 0, 1, 0)));
|
||||
|
||||
UpdateSamplingParameters(initialize: true);
|
||||
UpdateSamplingParameters(null, initialize: true);
|
||||
}
|
||||
|
||||
internal virtual void Enable()
|
||||
@@ -553,11 +622,10 @@ namespace WaveHarmonic.Crest
|
||||
internal virtual void Destroy()
|
||||
{
|
||||
// Release resources and destroy object to avoid reference leak.
|
||||
_Targets?.RunLambda(x =>
|
||||
{
|
||||
if (x != null) x.Release();
|
||||
Helpers.Destroy(x);
|
||||
});
|
||||
if (DataTexture != null) DataTexture.Release();
|
||||
Helpers.Destroy(DataTexture);
|
||||
|
||||
_AdditionalCameraData.Clear();
|
||||
}
|
||||
|
||||
internal virtual void AfterExecute()
|
||||
@@ -567,10 +635,11 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
private protected virtual void Allocate()
|
||||
{
|
||||
_Targets = new(BufferCount, CreateLodDataTextures);
|
||||
_Targets.RunLambda(Clear);
|
||||
// Use per-camera data.
|
||||
DataTexture = CreateLodDataTextures();
|
||||
Clear(DataTexture);
|
||||
|
||||
// Bind globally once here on init, which will bind to all graphics shaders (not compute)
|
||||
// Bind globally once here on init, which will bind to all shaders.
|
||||
Shader.SetGlobalTexture(_TextureShaderID, DataTexture);
|
||||
|
||||
_ReAllocateTexture = false;
|
||||
@@ -600,23 +669,21 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
int GetResolution() => _OverrideResolution || Water == null ? _Resolution : Water.LodResolution;
|
||||
|
||||
private protected void ReAllocate()
|
||||
private protected virtual void ReAllocate()
|
||||
{
|
||||
if (!Enabled) return;
|
||||
CompatibleTextureFormat = Helpers.GetCompatibleTextureFormat(RequestedTextureFormat, s_GraphicsFormatUsage, Name, NeedToReadWriteTextureData);
|
||||
var descriptor = _Targets.Current.descriptor;
|
||||
CompatibleTextureFormat = Helpers.GetCompatibleTextureFormat(RequestedTextureFormat, Helpers.s_DataGraphicsFormatUsage, Name, NeedToReadWriteTextureData);
|
||||
var descriptor = DataTexture.descriptor;
|
||||
descriptor.height = descriptor.width = Resolution;
|
||||
descriptor.graphicsFormat = CompatibleTextureFormat;
|
||||
_Targets.RunLambda(texture =>
|
||||
{
|
||||
texture.Release();
|
||||
texture.descriptor = descriptor;
|
||||
texture.Create();
|
||||
});
|
||||
descriptor.enableRandomWrite = NeedToReadWriteTextureData;
|
||||
DataTexture.Release();
|
||||
DataTexture.descriptor = descriptor;
|
||||
DataTexture.Create();
|
||||
|
||||
_ReAllocateTexture = false;
|
||||
|
||||
UpdateSamplingParameters(initialize: true);
|
||||
UpdateSamplingParameters(null, initialize: true);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
@@ -628,6 +695,7 @@ namespace WaveHarmonic.Crest
|
||||
case nameof(_Enabled):
|
||||
SetEnabled((bool)previousValue, _Enabled);
|
||||
break;
|
||||
case nameof(_Blur):
|
||||
case nameof(_Resolution):
|
||||
case nameof(_OverrideResolution):
|
||||
case nameof(_TextureFormat):
|
||||
@@ -639,6 +707,45 @@ namespace WaveHarmonic.Crest
|
||||
#endif
|
||||
}
|
||||
|
||||
partial class Lod
|
||||
{
|
||||
readonly Dictionary<Camera, BufferedData<Vector4[]>> _AdditionalCameraData = new();
|
||||
|
||||
internal virtual void LoadCameraData(Camera camera)
|
||||
{
|
||||
Queryable?.Initialize(_Water);
|
||||
|
||||
// For non-persistent sims, we do not need to store per camera data.
|
||||
if (!Persistent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_AdditionalCameraData.ContainsKey(camera))
|
||||
{
|
||||
_SamplingParameters = new(BufferCount, () => new Vector4[k_MaximumSlices]);
|
||||
_AdditionalCameraData.Add(camera, _SamplingParameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
_SamplingParameters = _AdditionalCameraData[camera];
|
||||
}
|
||||
}
|
||||
|
||||
internal virtual void StoreCameraData(Camera camera)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
internal virtual void RemoveCameraData(Camera camera)
|
||||
{
|
||||
if (_AdditionalCameraData.ContainsKey(camera))
|
||||
{
|
||||
_AdditionalCameraData.Remove(camera);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// API
|
||||
partial class Lod
|
||||
{
|
||||
@@ -657,29 +764,78 @@ namespace WaveHarmonic.Crest
|
||||
}
|
||||
}
|
||||
|
||||
interface IQueryableLod<out T> where T : IQueryProvider
|
||||
{
|
||||
string Name { get; }
|
||||
bool Enabled { get; }
|
||||
WaterRenderer Water { get; }
|
||||
int MaximumQueryCount { get; }
|
||||
float Texel { get; }
|
||||
LodQuerySource QuerySource { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The source of collisions (ie water shape).
|
||||
/// </summary>
|
||||
[@GenerateDoc]
|
||||
public enum LodQuerySource
|
||||
{
|
||||
/// <inheritdoc cref="Generated.LodQuerySource.None"/>
|
||||
[Tooltip("No query source.")]
|
||||
None,
|
||||
|
||||
/// <inheritdoc cref="Generated.LodQuerySource.GPU"/>
|
||||
[Tooltip("Uses AsyncGPUReadback to retrieve data from GPU to CPU.\n\nThis is the most optimal approach.")]
|
||||
GPU,
|
||||
|
||||
/// <inheritdoc cref="Generated.LodQuerySource.CPU"/>
|
||||
[Tooltip("Computes data entirely on the CPU.")]
|
||||
CPU,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base type for simulations with a provider.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The query provider.</typeparam>
|
||||
[System.Serializable]
|
||||
public abstract class Lod<T> : Lod where T : IQueryProvider
|
||||
public abstract partial class Lod<T> : Lod, IQueryableLod<T> where T : IQueryProvider
|
||||
{
|
||||
[@Space(10)]
|
||||
|
||||
[Tooltip("Where to obtain water data on CPU for physics / gameplay.")]
|
||||
[@GenerateAPI(Setter.Internal)]
|
||||
[@Filtered]
|
||||
[SerializeField]
|
||||
private protected LodQuerySource _QuerySource = LodQuerySource.GPU;
|
||||
|
||||
[Tooltip("Maximum number of queries that can be performed when using GPU queries.")]
|
||||
[@Show(nameof(_QuerySource), nameof(LodQuerySource.GPU))]
|
||||
[@GenerateAPI(Setter.None)]
|
||||
[@DecoratedField]
|
||||
[SerializeField]
|
||||
private protected int _MaximumQueryCount = QueryBase.k_DefaultMaximumQueryCount;
|
||||
|
||||
/// <summary>
|
||||
/// Provides data from the GPU to CPU.
|
||||
/// </summary>
|
||||
public T Provider { get; set; }
|
||||
private protected abstract T CreateProvider(bool enable);
|
||||
|
||||
internal override void SetGlobals(bool enable)
|
||||
WaterRenderer IQueryableLod<T>.Water => Water;
|
||||
string IQueryableLod<T>.Name => Name;
|
||||
float IQueryableLod<T>.Texel => _Cascades[0]._Texel;
|
||||
|
||||
private protected abstract T CreateProvider(bool onEnable);
|
||||
|
||||
internal override void SetGlobals(bool onEnable)
|
||||
{
|
||||
base.SetGlobals(enable);
|
||||
base.SetGlobals(onEnable);
|
||||
// We should always have a provider (null provider if disabled).
|
||||
InitializeProvider(enable);
|
||||
InitializeProvider(onEnable);
|
||||
}
|
||||
|
||||
private protected void InitializeProvider(bool enable)
|
||||
private protected void InitializeProvider(bool onEnable)
|
||||
{
|
||||
Provider = CreateProvider(enable);
|
||||
Provider = CreateProvider(onEnable);
|
||||
// None providers are not IQueryable.
|
||||
Queryable = Provider as IQueryable;
|
||||
}
|
||||
@@ -689,4 +845,30 @@ namespace WaveHarmonic.Crest
|
||||
Queryable?.SendReadBack(_Water);
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
partial class Lod<T>
|
||||
{
|
||||
private protected void ResetQueryChange()
|
||||
{
|
||||
if (_Water == null || !_Water.isActiveAndEnabled || !_Enabled) return;
|
||||
Queryable?.CleanUp();
|
||||
InitializeProvider(true);
|
||||
}
|
||||
|
||||
[@OnChange]
|
||||
private protected override void OnChange(string path, object previous)
|
||||
{
|
||||
base.OnChange(path, previous);
|
||||
|
||||
switch (path)
|
||||
{
|
||||
case nameof(_QuerySource):
|
||||
case nameof(_MaximumQueryCount):
|
||||
ResetQueryChange();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user