升级6.4.升级水,升级天气
This commit is contained in:
@@ -1,13 +1,15 @@
|
||||
// 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;
|
||||
|
||||
namespace WaveHarmonic.Crest
|
||||
{
|
||||
abstract class BakedWaveData : ScriptableObject
|
||||
abstract class BakedWaveData : CustomScriptableObject
|
||||
{
|
||||
public abstract ICollisionProvider CreateCollisionProvider();
|
||||
public abstract float WindSpeed { get; }
|
||||
@@ -20,6 +22,7 @@ namespace WaveHarmonic.Crest
|
||||
/// <summary>
|
||||
/// The source of collisions (ie water shape).
|
||||
/// </summary>
|
||||
[System.Obsolete("Please use QuerySource and LodQuerySource.")]
|
||||
[@GenerateDoc]
|
||||
public enum CollisionSource
|
||||
{
|
||||
@@ -67,13 +70,9 @@ namespace WaveHarmonic.Crest
|
||||
{
|
||||
// NOTE: numbers must be in order for defaults to work (everything first).
|
||||
|
||||
/// <inheritdoc cref="Generated.CollisionLayers.Everything"/>
|
||||
[Tooltip("All layers.")]
|
||||
Everything = -1,
|
||||
|
||||
/// <inheritdoc cref="Generated.CollisionLayers.Nothing"/>
|
||||
[Tooltip("No extra layers (ie single layer).")]
|
||||
Nothing,
|
||||
Nothing = 0,
|
||||
|
||||
/// <inheritdoc cref="Generated.CollisionLayers.DynamicWaves"/>
|
||||
[Tooltip("Separate layer for dynamic waves.\n\nDynamic waves are normally combined together for efficiency. By enabling this layer, dynamic waves are combined and added in a separate pass.")]
|
||||
@@ -82,6 +81,29 @@ namespace WaveHarmonic.Crest
|
||||
/// <inheritdoc cref="Generated.CollisionLayers.Displacement"/>
|
||||
[Tooltip("Extra displacement layer for visual displacement.")]
|
||||
Displacement = 1 << 2,
|
||||
|
||||
/// <inheritdoc cref="Generated.CollisionLayers.Everything"/>
|
||||
[Tooltip("All layers.")]
|
||||
Everything = ~0,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The wave sampling method to determine quality and performance.
|
||||
/// </summary>
|
||||
[@GenerateDoc]
|
||||
public enum WaveSampling
|
||||
{
|
||||
/// <inheritdoc cref="Generated.WaveSampling.Automatic"/>
|
||||
[Tooltip("Automatically chooses the other options as needed (512+ resolution needs precision).")]
|
||||
Automatic,
|
||||
|
||||
/// <inheritdoc cref="Generated.WaveSampling.Performance"/>
|
||||
[Tooltip("Reduces samples by copying waves from higher LODs to lower LODs.\n\nBest for resolutions lower than 512.")]
|
||||
Performance,
|
||||
|
||||
/// <inheritdoc cref="Generated.WaveSampling.Precision"/>
|
||||
[Tooltip("Samples directly from the wave buffers to preserve wave quality.\n\nNeeded for higher resolutions (512+). Higher LOD counts can also benefit with this enabled.")]
|
||||
Precision,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -108,14 +130,33 @@ namespace WaveHarmonic.Crest
|
||||
[@FilterEnum(nameof(_TextureFormatMode), Filtered.Mode.Exclude, (int)LodTextureFormatMode.Automatic)]
|
||||
public sealed partial class AnimatedWavesLod : Lod<ICollisionProvider>
|
||||
{
|
||||
[Tooltip("Collision layers to enable.\n\nSome layers will have overhead with CPU, GPU and memory.")]
|
||||
[@Enable(nameof(_QuerySource), nameof(LodQuerySource.GPU))]
|
||||
[@GenerateAPI]
|
||||
[@DecoratedField, SerializeField]
|
||||
internal CollisionLayers _CollisionLayers = CollisionLayers.Everything;
|
||||
|
||||
[@Enable(nameof(_QuerySource), nameof(LodQuerySource.CPU))]
|
||||
[@DecoratedField, SerializeField]
|
||||
internal BakedWaveData _BakedWaveData;
|
||||
|
||||
[@Space(10)]
|
||||
|
||||
[Tooltip("Shifts wavelengths to maintain quality for higher resolutions.\n\nSet this to 2 to improve wave quality. In some cases like flowing rivers, this can make a substantial difference to visual stability. We recommend doubling the Resolution on the WaterRenderer component to preserve detail after making this change.")]
|
||||
[@Range(1f, 4f)]
|
||||
[Tooltip("The wave sampling method to determine quality and performance.")]
|
||||
[@GenerateAPI]
|
||||
[@DecoratedField]
|
||||
[SerializeField]
|
||||
internal WaveSampling _WaveSampling;
|
||||
|
||||
[Tooltip("Shifts wavelengths to maintain quality for higher resolutions.\n\nSet this to 2 to improve wave quality. In some cases like flowing rivers, this can make a substantial difference to visual stability. We recommend doubling the Resolution on the WaterRenderer component to preserve detail after making this change.")]
|
||||
[@Enable(nameof(_WaveSampling), nameof(WaveSampling.Performance))]
|
||||
[@Range(1f, 4f)]
|
||||
[@GenerateAPI(Getter.Custom)]
|
||||
[SerializeField]
|
||||
float _WaveResolutionMultiplier = 1f;
|
||||
|
||||
[@Space(10)]
|
||||
|
||||
[Tooltip("How much waves are dampened in shallow water.")]
|
||||
[@Range(0f, 1f)]
|
||||
[@GenerateAPI]
|
||||
@@ -129,30 +170,6 @@ namespace WaveHarmonic.Crest
|
||||
float _ShallowsMaximumDepth = 1000f;
|
||||
|
||||
|
||||
[@Heading("Collisions")]
|
||||
|
||||
[Tooltip("Where to obtain water shape on CPU for physics / gameplay.")]
|
||||
[@GenerateAPI(Setter.Internal)]
|
||||
[@DecoratedField, SerializeField]
|
||||
internal CollisionSource _CollisionSource = CollisionSource.GPU;
|
||||
|
||||
[Tooltip("Collision layers to enable.\n\nSome layers will have overhead with CPU, GPU and memory.")]
|
||||
[@Predicated(nameof(_CollisionSource), inverted: true, nameof(CollisionSource.GPU))]
|
||||
[@GenerateAPI]
|
||||
[@DecoratedField, SerializeField]
|
||||
internal CollisionLayers _CollisionLayers = CollisionLayers.Everything;
|
||||
|
||||
[Tooltip("Maximum number of wave queries that can be performed when using GPU queries.")]
|
||||
[@Predicated(nameof(_CollisionSource), true, nameof(CollisionSource.GPU))]
|
||||
[@GenerateAPI(Setter.None)]
|
||||
[@DecoratedField, SerializeField]
|
||||
int _MaximumQueryCount = QueryBase.k_DefaultMaximumQueryCount;
|
||||
|
||||
[@Predicated(nameof(_CollisionSource), true, nameof(CollisionSource.CPU))]
|
||||
[@DecoratedField, SerializeField]
|
||||
internal BakedWaveData _BakedWaveData;
|
||||
|
||||
|
||||
const string k_DrawCombine = "Combine";
|
||||
|
||||
|
||||
@@ -160,7 +177,6 @@ namespace WaveHarmonic.Crest
|
||||
{
|
||||
public static readonly int s_WaveBuffer = Shader.PropertyToID("_Crest_WaveBuffer");
|
||||
public static readonly int s_DynamicWavesTarget = Shader.PropertyToID("_Crest_DynamicWavesTarget");
|
||||
public static readonly int s_AnimatedWavesTarget = Shader.PropertyToID("_Crest_AnimatedWavesTarget");
|
||||
public static readonly int s_AttenuationInShallows = Shader.PropertyToID("_Crest_AttenuationInShallows");
|
||||
}
|
||||
|
||||
@@ -171,6 +187,9 @@ namespace WaveHarmonic.Crest
|
||||
/// </summary>
|
||||
internal static bool s_Combine = true;
|
||||
|
||||
WaterResources.ShapeCombineCompute _CombineShader;
|
||||
RenderTexture _PersistentDataTexture;
|
||||
|
||||
internal override string ID => "AnimatedWaves";
|
||||
internal override string Name => "Animated Waves";
|
||||
internal override Color GizmoColor => s_GizmoColor;
|
||||
@@ -187,17 +206,13 @@ namespace WaveHarmonic.Crest
|
||||
_ => throw new System.NotImplementedException(),
|
||||
};
|
||||
|
||||
ComputeShader _CombineShader;
|
||||
|
||||
int _KernalShapeCombine = -1;
|
||||
int _KernalShapeCombine_DISABLE_COMBINE = -1;
|
||||
int _KernalShapeCombine_FLOW_ON = -1;
|
||||
int _KernalShapeCombine_FLOW_ON_DISABLE_COMBINE = -1;
|
||||
int _KernalShapeCombine_DYNAMIC_WAVE_SIM_ON = -1;
|
||||
int _KernalShapeCombine_DYNAMIC_WAVE_SIM_ON_DISABLE_COMBINE = -1;
|
||||
int _KernalShapeCombine_FLOW_ON_DYNAMIC_WAVE_SIM_ON = -1;
|
||||
int _KernalShapeCombine_FLOW_ON_DYNAMIC_WAVE_SIM_ON_DISABLE_COMBINE = -1;
|
||||
|
||||
internal bool PreserveWaveQuality => WaveSampling switch
|
||||
{
|
||||
WaveSampling.Automatic => Resolution >= 512,
|
||||
WaveSampling.Performance => false,
|
||||
WaveSampling.Precision => true,
|
||||
_ => throw new System.NotImplementedException(),
|
||||
};
|
||||
|
||||
internal AnimatedWavesLod()
|
||||
{
|
||||
@@ -208,35 +223,67 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
internal override void Initialize()
|
||||
{
|
||||
_CombineShader = WaterResources.Instance.Compute._ShapeCombine;
|
||||
if (_CombineShader == null)
|
||||
_CombineShader = WaterResources.Instance._ComputeLibrary._ShapeCombineCompute;
|
||||
if (_CombineShader._Shader == null)
|
||||
{
|
||||
_Valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
base.Initialize();
|
||||
|
||||
if (Persistent && !_Water.IsMultipleViewpointMode)
|
||||
{
|
||||
_PersistentDataTexture = CreateLodDataTextures();
|
||||
}
|
||||
}
|
||||
|
||||
private protected override void Allocate()
|
||||
internal override void Destroy()
|
||||
{
|
||||
base.Allocate();
|
||||
base.Destroy();
|
||||
|
||||
_KernalShapeCombine = _CombineShader.FindKernel("ShapeCombine");
|
||||
_KernalShapeCombine_DISABLE_COMBINE = _CombineShader.FindKernel("ShapeCombine_DISABLE_COMBINE");
|
||||
_KernalShapeCombine_FLOW_ON = _CombineShader.FindKernel("ShapeCombine_FLOW_ON");
|
||||
_KernalShapeCombine_FLOW_ON_DISABLE_COMBINE = _CombineShader.FindKernel("ShapeCombine_FLOW_ON_DISABLE_COMBINE");
|
||||
_KernalShapeCombine_DYNAMIC_WAVE_SIM_ON = _CombineShader.FindKernel("ShapeCombine_DYNAMIC_WAVE_SIM_ON");
|
||||
_KernalShapeCombine_DYNAMIC_WAVE_SIM_ON_DISABLE_COMBINE = _CombineShader.FindKernel("ShapeCombine_DYNAMIC_WAVE_SIM_ON_DISABLE_COMBINE");
|
||||
_KernalShapeCombine_FLOW_ON_DYNAMIC_WAVE_SIM_ON = _CombineShader.FindKernel("ShapeCombine_FLOW_ON_DYNAMIC_WAVE_SIM_ON");
|
||||
_KernalShapeCombine_FLOW_ON_DYNAMIC_WAVE_SIM_ON_DISABLE_COMBINE = _CombineShader.FindKernel("ShapeCombine_FLOW_ON_DYNAMIC_WAVE_SIM_ON_DISABLE_COMBINE");
|
||||
if (_PersistentDataTexture != null) _PersistentDataTexture.Release();
|
||||
Helpers.Destroy(_PersistentDataTexture);
|
||||
|
||||
foreach (var data in _AdditionalCameraData.Values)
|
||||
{
|
||||
if (data != null) data.Release();
|
||||
Helpers.Destroy(data);
|
||||
}
|
||||
|
||||
_AdditionalCameraData.Clear();
|
||||
}
|
||||
|
||||
internal override void SetGlobals(bool enable)
|
||||
{
|
||||
base.SetGlobals(enable);
|
||||
|
||||
if (_Water.IsRunningWithoutGraphics)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Persistent)
|
||||
{
|
||||
Shader.SetGlobalTexture(_TextureSourceShaderID, enable && Enabled ? _PersistentDataTexture : NullTexture);
|
||||
}
|
||||
}
|
||||
|
||||
internal override void BuildCommandBuffer(WaterRenderer water, CommandBuffer buffer)
|
||||
{
|
||||
buffer.BeginSample(ID);
|
||||
|
||||
FlipBuffers();
|
||||
FlipBuffers(buffer);
|
||||
|
||||
// Flip textures
|
||||
if (Persistent)
|
||||
{
|
||||
(_PersistentDataTexture, DataTexture) = (DataTexture, _PersistentDataTexture);
|
||||
|
||||
// Update current and previous. Latter for MVs and/or VFX.
|
||||
buffer.SetGlobalTexture(_TextureSourceShaderID, _PersistentDataTexture);
|
||||
buffer.SetGlobalTexture(_TextureShaderID, DataTexture);
|
||||
}
|
||||
|
||||
Shader.SetGlobalFloat(ShaderIDs.s_AttenuationInShallows, _AttenuationInShallows);
|
||||
|
||||
@@ -244,6 +291,18 @@ namespace WaveHarmonic.Crest
|
||||
buffer.GetTemporaryRT(ShaderIDs.s_WaveBuffer, DataTexture.descriptor);
|
||||
CoreUtils.SetRenderTarget(buffer, ShaderIDs.s_WaveBuffer, ClearFlag.Color, ClearColor);
|
||||
|
||||
// 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, DataTexture.graphicsFormat);
|
||||
wrapper.SetTexture(Crest.ShaderIDs.s_Target, ShaderIDs.s_WaveBuffer);
|
||||
wrapper.SetVector(Crest.ShaderIDs.s_ClearMask, Color.white);
|
||||
wrapper.SetVector(Crest.ShaderIDs.s_ClearColor, ClearColor);
|
||||
wrapper.Dispatch(Resolution / k_ThreadGroupSizeX, Resolution / k_ThreadGroupSizeY, Slices);
|
||||
}
|
||||
|
||||
// LOD dependent data.
|
||||
// Write to per-octave _WaveBuffers. Not the same as _AnimatedWaves.
|
||||
// Draw any data with lod preference.
|
||||
@@ -254,54 +313,53 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
// Combine the LODs - copy results from biggest LOD down to LOD 0
|
||||
{
|
||||
var combineShaderKernel = _KernalShapeCombine;
|
||||
var combineShaderKernel_lastLOD = _KernalShapeCombine_DISABLE_COMBINE;
|
||||
{
|
||||
var isFlowOn = _Water._FlowLod.Enabled;
|
||||
var isDynamicWavesOn = _Water._DynamicWavesLod.Enabled && !_CollisionLayers.HasFlag(CollisionLayers.DynamicWaves);
|
||||
var wrapper = new PropertyWrapperCompute
|
||||
(
|
||||
buffer,
|
||||
_CombineShader._Shader,
|
||||
PreserveWaveQuality
|
||||
? _CombineShader._CopyAnimatedWavesKernel
|
||||
: _CombineShader._CombineAnimatedWavesKernel
|
||||
);
|
||||
|
||||
// Set the shader kernels that we will use.
|
||||
if (isFlowOn && isDynamicWavesOn)
|
||||
{
|
||||
combineShaderKernel = _KernalShapeCombine_FLOW_ON_DYNAMIC_WAVE_SIM_ON;
|
||||
combineShaderKernel_lastLOD = _KernalShapeCombine_FLOW_ON_DYNAMIC_WAVE_SIM_ON_DISABLE_COMBINE;
|
||||
}
|
||||
else if (isFlowOn)
|
||||
{
|
||||
combineShaderKernel = _KernalShapeCombine_FLOW_ON;
|
||||
combineShaderKernel_lastLOD = _KernalShapeCombine_FLOW_ON_DISABLE_COMBINE;
|
||||
}
|
||||
else if (isDynamicWavesOn)
|
||||
{
|
||||
combineShaderKernel = _KernalShapeCombine_DYNAMIC_WAVE_SIM_ON;
|
||||
combineShaderKernel_lastLOD = _KernalShapeCombine_DYNAMIC_WAVE_SIM_ON_DISABLE_COMBINE;
|
||||
}
|
||||
if (_Water._DynamicWavesLod.Enabled)
|
||||
{
|
||||
_Water._DynamicWavesLod.Bind(wrapper);
|
||||
}
|
||||
|
||||
buffer.BeginSample(k_DrawCombine);
|
||||
// Start with last LOD which does not combine.
|
||||
wrapper.SetKeyword(_CombineShader._CombineKeyword, false);
|
||||
wrapper.SetKeyword(_CombineShader._DynamicWavesKeyword, _Water._DynamicWavesLod.Enabled && !PreserveWaveQuality && !_CollisionLayers.HasFlag(CollisionLayers.DynamicWaves));
|
||||
|
||||
// Combine waves.
|
||||
for (var slice = lastSlice; slice >= 0; slice--)
|
||||
// The per-octave wave buffers we read from.
|
||||
wrapper.SetTexture(ShaderIDs.s_WaveBuffer, ShaderIDs.s_WaveBuffer);
|
||||
|
||||
// Set the animated waves texture where we read/write to combine the results.
|
||||
wrapper.SetTexture(Crest.ShaderIDs.s_Target, DataTexture);
|
||||
|
||||
if (PreserveWaveQuality)
|
||||
{
|
||||
var kernel = slice < lastSlice && s_Combine
|
||||
? combineShaderKernel : combineShaderKernel_lastLOD;
|
||||
|
||||
var wrapper = new PropertyWrapperCompute(buffer, _CombineShader, kernel);
|
||||
|
||||
// The per-octave wave buffers we read from.
|
||||
wrapper.SetTexture(ShaderIDs.s_WaveBuffer, ShaderIDs.s_WaveBuffer);
|
||||
|
||||
if (_Water._DynamicWavesLod.Enabled) _Water._DynamicWavesLod.Bind(wrapper);
|
||||
|
||||
// Set the animated waves texture where we read/write to combine the results. Use
|
||||
// compute suffix to avoid collision as a file already uses the normal name.
|
||||
wrapper.SetTexture(Crest.ShaderIDs.s_Target, DataTexture);
|
||||
wrapper.SetInteger(Lod.ShaderIDs.s_LodIndex, slice);
|
||||
|
||||
wrapper.Dispatch(threadSize, threadSize, 1);
|
||||
wrapper.Dispatch(threadSize, threadSize, Slices);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.BeginSample(k_DrawCombine);
|
||||
|
||||
buffer.EndSample(k_DrawCombine);
|
||||
// Combine waves.
|
||||
for (var slice = lastSlice; slice >= 0; slice--)
|
||||
{
|
||||
wrapper.SetInteger(Lod.ShaderIDs.s_LodIndex, slice);
|
||||
wrapper.Dispatch(threadSize, threadSize, 1);
|
||||
|
||||
if (slice == lastSlice)
|
||||
{
|
||||
// From here on, use combine.
|
||||
wrapper.SetKeyword(_CombineShader._CombineKeyword, s_Combine);
|
||||
}
|
||||
}
|
||||
|
||||
buffer.EndSample(k_DrawCombine);
|
||||
}
|
||||
}
|
||||
|
||||
buffer.ReleaseTemporaryRT(ShaderIDs.s_WaveBuffer);
|
||||
@@ -312,20 +370,15 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
// Alpha channel is cleared in combine step, but if any inputs draw in post-combine
|
||||
// step then alpha may have data.
|
||||
var clear = WaterResources.Instance.Compute._Clear;
|
||||
if (drawn && clear != null)
|
||||
if (drawn && WaterResources.Instance.Compute._Clear != null)
|
||||
{
|
||||
buffer.SetComputeTextureParam(clear, 0, Crest.ShaderIDs.s_Target, DataTexture);
|
||||
buffer.SetComputeVectorParam(clear, Crest.ShaderIDs.s_ClearMask, Color.black);
|
||||
buffer.SetComputeVectorParam(clear, Crest.ShaderIDs.s_ClearColor, Color.clear);
|
||||
buffer.DispatchCompute
|
||||
(
|
||||
clear,
|
||||
0,
|
||||
Resolution / k_ThreadGroupSizeX,
|
||||
Resolution / k_ThreadGroupSizeY,
|
||||
Slices
|
||||
);
|
||||
var compute = WaterResources.Instance._ComputeLibrary._ClearCompute;
|
||||
var wrapper = new PropertyWrapperCompute(buffer, compute._Shader, compute._KernelClearTarget);
|
||||
compute.SetVariantForFormat(wrapper, DataTexture.graphicsFormat);
|
||||
wrapper.SetTexture(Crest.ShaderIDs.s_Target, DataTexture);
|
||||
wrapper.SetVector(Crest.ShaderIDs.s_ClearMask, Color.black);
|
||||
wrapper.SetVector(Crest.ShaderIDs.s_ClearColor, Color.clear);
|
||||
wrapper.Dispatch(Resolution / k_ThreadGroupSizeX, Resolution / k_ThreadGroupSizeY, Slices);
|
||||
}
|
||||
|
||||
// Pack height data into alpha channel.
|
||||
@@ -355,15 +408,21 @@ namespace WaveHarmonic.Crest
|
||||
}
|
||||
|
||||
// Transfer Dynamic Waves to Animated Waves.
|
||||
if (_CollisionLayers.HasFlag(CollisionLayers.DynamicWaves) && _Water._DynamicWavesLod.Enabled)
|
||||
if ((_CollisionLayers.HasFlag(CollisionLayers.DynamicWaves) || PreserveWaveQuality) && _Water._DynamicWavesLod.Enabled)
|
||||
{
|
||||
buffer.BeginSample(k_DrawCombine);
|
||||
// Clearing not required as we overwrite enter texture.
|
||||
buffer.GetTemporaryRT(ShaderIDs.s_DynamicWavesTarget, DataTexture.descriptor);
|
||||
|
||||
var wrapper = new PropertyWrapperCompute(buffer, _CombineShader, 9);
|
||||
var wrapper = new PropertyWrapperCompute(buffer, _CombineShader._Shader, _CombineShader._CombineDynamicWavesKernel);
|
||||
|
||||
wrapper.SetTexture(ShaderIDs.s_DynamicWavesTarget, ShaderIDs.s_DynamicWavesTarget);
|
||||
// Flow keyword is already set, and Dynamic Waves already bound. If binding Dynamic
|
||||
// Waves becomes kernel specific (eg binding textures), then we need to rebind.
|
||||
|
||||
// Start with last LOD which does not combine.
|
||||
wrapper.SetKeyword(_CombineShader._CombineKeyword, false);
|
||||
|
||||
wrapper.SetTexture(Crest.ShaderIDs.s_Target, ShaderIDs.s_DynamicWavesTarget);
|
||||
|
||||
_Water._DynamicWavesLod.Bind(wrapper);
|
||||
|
||||
@@ -373,18 +432,21 @@ namespace WaveHarmonic.Crest
|
||||
wrapper.SetInteger(Lod.ShaderIDs.s_LodIndex, slice);
|
||||
wrapper.Dispatch(threadSize, threadSize, 1);
|
||||
|
||||
// Change to kernel with combine enabled.
|
||||
if (slice == lastSlice)
|
||||
{
|
||||
wrapper = new(buffer, _CombineShader, 8);
|
||||
// From here on, use combine.
|
||||
wrapper.SetKeyword(_CombineShader._CombineKeyword, s_Combine);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy Dynamic Waves displacement into Animated Waves.
|
||||
if (WaterResources.Instance.Compute._Blit != null)
|
||||
{
|
||||
wrapper = new(buffer, _CombineShader, 10);
|
||||
wrapper.SetTexture(ShaderIDs.s_AnimatedWavesTarget, DataTexture);
|
||||
wrapper.SetTexture(ShaderIDs.s_DynamicWavesTarget, ShaderIDs.s_DynamicWavesTarget);
|
||||
var compute = WaterResources.Instance._ComputeLibrary._BlitCompute;
|
||||
wrapper = new(buffer, compute._Shader, 0);
|
||||
compute.SetVariantForFormat(wrapper, DataTexture.graphicsFormat);
|
||||
wrapper.SetTexture(Crest.ShaderIDs.s_Source, ShaderIDs.s_DynamicWavesTarget);
|
||||
wrapper.SetTexture(Crest.ShaderIDs.s_Target, DataTexture);
|
||||
wrapper.Dispatch(threadSize, threadSize, Slices);
|
||||
}
|
||||
|
||||
@@ -393,7 +455,10 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
// Query collisions including Dynamic Waves.
|
||||
// Does not require copying the water level as they are added with zero alpha.
|
||||
Provider.UpdateQueries(_Water, CollisionLayer.AfterDynamicWaves);
|
||||
if (_CollisionLayers.HasFlag(CollisionLayers.DynamicWaves))
|
||||
{
|
||||
Provider.UpdateQueries(_Water, CollisionLayer.AfterDynamicWaves);
|
||||
}
|
||||
}
|
||||
|
||||
if (_CollisionLayers.HasFlag(CollisionLayers.Displacement))
|
||||
@@ -408,13 +473,6 @@ namespace WaveHarmonic.Crest
|
||||
Queryable?.UpdateQueries(_Water);
|
||||
}
|
||||
|
||||
if (BufferCount > 1)
|
||||
{
|
||||
// Update current and previous. Latter for MVs and/or VFX.
|
||||
Shader.SetGlobalTexture(_TextureSourceShaderID, _Targets.Previous(1));
|
||||
Shader.SetGlobalTexture(_TextureShaderID, DataTexture);
|
||||
}
|
||||
|
||||
buffer.EndSample(ID);
|
||||
}
|
||||
|
||||
@@ -426,50 +484,59 @@ namespace WaveHarmonic.Crest
|
||||
/// <summary>
|
||||
/// Provides water shape to CPU.
|
||||
/// </summary>
|
||||
private protected override ICollisionProvider CreateProvider(bool enable)
|
||||
private protected override ICollisionProvider CreateProvider(bool onEnable)
|
||||
{
|
||||
ICollisionProvider result = null;
|
||||
ICollisionProvider provider = ICollisionProvider.None;
|
||||
|
||||
Queryable?.CleanUp();
|
||||
|
||||
if (!enable)
|
||||
// Respect user choice and early exit. If not in OnEnable, then none provider.
|
||||
// Do not check Enabled, as it includes _Valid which checks for GPU.
|
||||
if (!_Enabled || !onEnable)
|
||||
{
|
||||
return ICollisionProvider.None;
|
||||
return provider;
|
||||
}
|
||||
|
||||
switch (_CollisionSource)
|
||||
var source = QuerySource;
|
||||
|
||||
if (_Water.Surface.IsQuadMesh)
|
||||
{
|
||||
case CollisionSource.None:
|
||||
result = ICollisionProvider.None;
|
||||
break;
|
||||
case CollisionSource.GPU:
|
||||
if (_Valid && !_Water.IsRunningWithoutGraphics)
|
||||
source = LodQuerySource.None;
|
||||
}
|
||||
|
||||
switch (source)
|
||||
{
|
||||
case LodQuerySource.GPU:
|
||||
{
|
||||
if (_Valid)
|
||||
{
|
||||
result = new CollisionQueryWithPasses(_Water);
|
||||
provider = ICollisionProvider.Create(_Water);
|
||||
}
|
||||
|
||||
if (_Water.IsRunningWithoutGraphics)
|
||||
{
|
||||
Debug.LogError($"Crest: GPU queries not supported in headless/batch mode. To resolve, assign an Animated Wave Settings asset to the {nameof(WaterRenderer)} component and set the Collision Source to be a CPU option.");
|
||||
Debug.LogError("Crest: GPU queries requires a GPU. Please consider CPU queries if running from a server without a GPU.");
|
||||
}
|
||||
|
||||
break;
|
||||
case CollisionSource.CPU:
|
||||
}
|
||||
case LodQuerySource.CPU:
|
||||
{
|
||||
if (_BakedWaveData != null)
|
||||
{
|
||||
result = _BakedWaveData.CreateCollisionProvider();
|
||||
provider = _BakedWaveData.CreateCollisionProvider();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
// This should not be hit, but can be if compute shaders aren't loaded correctly.
|
||||
// They will print out appropriate errors. Don't just return null and have null reference
|
||||
// exceptions spamming the logs.
|
||||
return ICollisionProvider.None;
|
||||
}
|
||||
// This should not be hit, but can be if compute shaders aren't loaded correctly.
|
||||
// They will print out appropriate errors. Don't just return null and have null
|
||||
// reference exceptions spamming the logs.
|
||||
provider ??= ICollisionProvider.None;
|
||||
|
||||
return result;
|
||||
return provider;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -484,15 +551,17 @@ namespace WaveHarmonic.Crest
|
||||
public readonly float _ViewerAltitudeLevelAlpha;
|
||||
public readonly int _Slice;
|
||||
public readonly int _Slices;
|
||||
public readonly bool _HighQualityCombine;
|
||||
|
||||
public WavelengthFilter(WaterRenderer water, int slice)
|
||||
public WavelengthFilter(WaterRenderer water, int slice, int resolution)
|
||||
{
|
||||
_Slice = slice;
|
||||
_Slices = water.LodLevels;
|
||||
_Maximum = water.MaximumWavelength(slice);
|
||||
_Maximum = water.MaximumWavelength(slice, resolution);
|
||||
_Minimum = _Maximum * 0.5f;
|
||||
_TransitionThreshold = water.MaximumWavelength(_Slices - 1) * 0.5f;
|
||||
_TransitionThreshold = water.MaximumWavelength(_Slices - 1, resolution) * 0.5f;
|
||||
_ViewerAltitudeLevelAlpha = water.ViewerAltitudeLevelAlpha;
|
||||
_HighQualityCombine = water.AnimatedWavesLod.PreserveWaveQuality;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -513,7 +582,7 @@ namespace WaveHarmonic.Crest
|
||||
// If approaching end of lod chain, start smoothly transitioning any large wavelengths across last two lods
|
||||
if (wavelength >= filter._TransitionThreshold)
|
||||
{
|
||||
if (filter._Slice == filter._Slices - 2)
|
||||
if (filter._Slice == filter._Slices - 2 && !filter._HighQualityCombine)
|
||||
{
|
||||
return 1f - filter._ViewerAltitudeLevelAlpha;
|
||||
}
|
||||
@@ -529,12 +598,12 @@ namespace WaveHarmonic.Crest
|
||||
return 1f;
|
||||
}
|
||||
|
||||
return 0f;
|
||||
return filter._HighQualityCombine ? 1f : 0f;
|
||||
}
|
||||
|
||||
internal static float FilterByWavelength(WaterRenderer water, int slice, float wavelength)
|
||||
internal static float FilterByWavelength(WaterRenderer water, int slice, float wavelength, int resolution)
|
||||
{
|
||||
return FilterByWavelength(new(water, slice), wavelength);
|
||||
return FilterByWavelength(new(water, slice, resolution), wavelength);
|
||||
}
|
||||
|
||||
|
||||
@@ -550,8 +619,83 @@ namespace WaveHarmonic.Crest
|
||||
{
|
||||
s_Inputs.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Multiple Viewpoints
|
||||
partial class AnimatedWavesLod
|
||||
{
|
||||
readonly Dictionary<Camera, RenderTexture> _AdditionalCameraData = new();
|
||||
|
||||
internal override void LoadCameraData(Camera camera)
|
||||
{
|
||||
base.LoadCameraData(camera);
|
||||
|
||||
if (!Persistent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_AdditionalCameraData.ContainsKey(camera))
|
||||
{
|
||||
_PersistentDataTexture = CreateLodDataTextures();
|
||||
Clear(_PersistentDataTexture);
|
||||
_AdditionalCameraData.Add(camera, _PersistentDataTexture);
|
||||
}
|
||||
else
|
||||
{
|
||||
_PersistentDataTexture = _AdditionalCameraData[camera];
|
||||
}
|
||||
}
|
||||
|
||||
internal override void StoreCameraData(Camera camera)
|
||||
{
|
||||
base.StoreCameraData(camera);
|
||||
|
||||
if (!Persistent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_AdditionalCameraData[camera] = _PersistentDataTexture;
|
||||
}
|
||||
|
||||
internal override void RemoveCameraData(Camera camera)
|
||||
{
|
||||
base.RemoveCameraData(camera);
|
||||
|
||||
if (_AdditionalCameraData.ContainsKey(camera))
|
||||
{
|
||||
var rt = _AdditionalCameraData[camera];
|
||||
if (rt != null) rt.Release();
|
||||
Helpers.Destroy(rt);
|
||||
_AdditionalCameraData.Remove(camera);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// API
|
||||
partial class AnimatedWavesLod
|
||||
{
|
||||
float GetWaveResolutionMultiplier()
|
||||
{
|
||||
return PreserveWaveQuality ? 1f : _WaveResolutionMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
partial class AnimatedWavesLod
|
||||
{
|
||||
[@HideInInspector]
|
||||
[@System.Obsolete("Please use QuerySource instead.")]
|
||||
[Tooltip("Where to obtain water shape on CPU for physics / gameplay.")]
|
||||
[@GenerateAPI(Setter.Internal)]
|
||||
[@DecoratedField, SerializeField]
|
||||
internal CollisionSource _CollisionSource = CollisionSource.GPU;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// Editor
|
||||
partial class AnimatedWavesLod
|
||||
{
|
||||
[@OnChange]
|
||||
private protected override void OnChange(string propertyPath, object previousValue)
|
||||
{
|
||||
@@ -560,13 +704,10 @@ namespace WaveHarmonic.Crest
|
||||
switch (propertyPath)
|
||||
{
|
||||
case nameof(_CollisionLayers):
|
||||
case nameof(_CollisionSource):
|
||||
if (_Water == null || !_Water.isActiveAndEnabled || !Enabled) return;
|
||||
Queryable?.CleanUp();
|
||||
InitializeProvider(true);
|
||||
ResetQueryChange();
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user