升级水插件
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
@@ -32,10 +32,11 @@ namespace WaveHarmonic.Crest
|
||||
get
|
||||
{
|
||||
var color = Color.clear;
|
||||
var surface = _Water.Surface;
|
||||
|
||||
if (_Water.Material != null)
|
||||
if (surface.Material != null && surface.Material.HasVector(WaterRenderer.ShaderIDs.s_Absorption))
|
||||
{
|
||||
color = _Water.Material.GetVector(WaterRenderer.ShaderIDs.s_Absorption);
|
||||
color = surface.Material.GetVector(WaterRenderer.ShaderIDs.s_Absorption);
|
||||
color.a = 0f;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
@@ -20,55 +20,39 @@ namespace WaveHarmonic.Crest
|
||||
/// <summary>
|
||||
/// The source of collisions (ie water shape).
|
||||
/// </summary>
|
||||
[@GenerateDoc]
|
||||
public enum CollisionSource
|
||||
{
|
||||
/// <summary>
|
||||
/// No collision source. Flat water.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.CollisionSource.None"/>
|
||||
[Tooltip("No collision source. Flat water.")]
|
||||
None = 0,
|
||||
|
||||
// GerstnerWavesCPU = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Uses AsyncGPUReadback to retrieve data from GPU to CPU.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the most optimal approach.
|
||||
/// </remarks>
|
||||
/// <inheritdoc cref="Generated.CollisionSource.GPU"/>
|
||||
[Tooltip("Uses AsyncGPUReadback to retrieve data from GPU to CPU.\n\nThis is the most optimal approach.")]
|
||||
GPU = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Computes data entirely on the CPU.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.CollisionSource.CPU"/>
|
||||
[Tooltip("Computes data entirely on the CPU.")]
|
||||
CPU = 3,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The pass to render displacement into.
|
||||
/// </summary>
|
||||
[@GenerateDoc]
|
||||
public enum DisplacementPass
|
||||
{
|
||||
/// <summary>
|
||||
/// Displacement that is dependent on an LOD (eg waves).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Uses filtering to determine which LOD to write to.
|
||||
/// </remarks>
|
||||
/// <inheritdoc cref="Generated.DisplacementPass.LodDependent"/>
|
||||
[Tooltip("Displacement that is dependent on an LOD (eg waves).\n\nUses filtering to determine which LOD to write to.")]
|
||||
LodDependent,
|
||||
|
||||
/// <summary>
|
||||
/// Renders to all LODs.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.DisplacementPass.LodIndependent"/>
|
||||
[Tooltip("Renders to all LODs.")]
|
||||
LodIndependent,
|
||||
|
||||
/// <summary>
|
||||
/// Renders to all LODs, but as a separate pass.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Typically used to render visual displacement which does not affect collisions.
|
||||
/// </remarks>
|
||||
/// <inheritdoc cref="Generated.DisplacementPass.LodIndependentLast"/>
|
||||
[Tooltip("Renders to all LODs, but as a separate pass.\n\nTypically used to render visual displacement which does not affect collisions.")]
|
||||
[InspectorName("Lod Independent (Last)")]
|
||||
LodIndependentLast,
|
||||
@@ -78,35 +62,24 @@ namespace WaveHarmonic.Crest
|
||||
/// Flags to enable extra collsion layers.
|
||||
/// </summary>
|
||||
[System.Flags]
|
||||
[@GenerateDoc]
|
||||
public enum CollisionLayers
|
||||
{
|
||||
// NOTE: numbers must be in order for defaults to work (everything first).
|
||||
|
||||
/// <summary>
|
||||
/// All layers.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.CollisionLayers.Everything"/>
|
||||
[Tooltip("All layers.")]
|
||||
Everything = -1,
|
||||
|
||||
/// <summary>
|
||||
/// No extra layers (ie single layer).
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.CollisionLayers.Nothing"/>
|
||||
[Tooltip("No extra layers (ie single layer).")]
|
||||
Nothing,
|
||||
|
||||
/// <summary>
|
||||
/// Separate layer for dynamic waves.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Dynamic waves are normally combined together for efficiency. By enabling this
|
||||
/// layer, dynamic waves are combined and added in a separate pass.
|
||||
/// </remarks>
|
||||
/// <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.")]
|
||||
DynamicWaves = 1 << 1,
|
||||
|
||||
/// <summary>
|
||||
/// Extra displacement layer for visual displacement.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.CollisionLayers.Displacement"/>
|
||||
[Tooltip("Extra displacement layer for visual displacement.")]
|
||||
Displacement = 1 << 2,
|
||||
}
|
||||
@@ -180,6 +153,9 @@ namespace WaveHarmonic.Crest
|
||||
internal BakedWaveData _BakedWaveData;
|
||||
|
||||
|
||||
const string k_DrawCombine = "Combine";
|
||||
|
||||
|
||||
internal static new partial class ShaderIDs
|
||||
{
|
||||
public static readonly int s_WaveBuffer = Shader.PropertyToID("_Crest_WaveBuffer");
|
||||
@@ -201,7 +177,6 @@ namespace WaveHarmonic.Crest
|
||||
private protected override bool NeedToReadWriteTextureData => true;
|
||||
private protected override Color ClearColor => Color.black;
|
||||
internal override int BufferCount => _Water.WriteMotionVectors ? 2 : 1;
|
||||
internal override bool RunsInHeadless => true;
|
||||
|
||||
// NOTE: Tried RGB111110Float but errors becomes visible. One option would be to use a UNORM setup.
|
||||
private protected override GraphicsFormat RequestedTextureFormat => _TextureFormatMode switch
|
||||
@@ -259,7 +234,7 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
internal override void BuildCommandBuffer(WaterRenderer water, CommandBuffer buffer)
|
||||
{
|
||||
buffer.BeginSample(Name);
|
||||
buffer.BeginSample(ID);
|
||||
|
||||
FlipBuffers();
|
||||
|
||||
@@ -267,8 +242,7 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
// Get temporary buffer to store waves. They will be copied in the combine pass.
|
||||
buffer.GetTemporaryRT(ShaderIDs.s_WaveBuffer, DataTexture.descriptor);
|
||||
buffer.SetRenderTarget(ShaderIDs.s_WaveBuffer, 0, CubemapFace.Unknown, -1);
|
||||
buffer.ClearRenderTarget(false, true, ClearColor);
|
||||
CoreUtils.SetRenderTarget(buffer, ShaderIDs.s_WaveBuffer, ClearFlag.Color, ClearColor);
|
||||
|
||||
// LOD dependent data.
|
||||
// Write to per-octave _WaveBuffers. Not the same as _AnimatedWaves.
|
||||
@@ -304,7 +278,7 @@ namespace WaveHarmonic.Crest
|
||||
}
|
||||
}
|
||||
|
||||
buffer.BeginSample("Combine");
|
||||
buffer.BeginSample(k_DrawCombine);
|
||||
|
||||
// Combine waves.
|
||||
for (var slice = lastSlice; slice >= 0; slice--)
|
||||
@@ -327,7 +301,7 @@ namespace WaveHarmonic.Crest
|
||||
wrapper.Dispatch(threadSize, threadSize, 1);
|
||||
}
|
||||
|
||||
buffer.EndSample("Combine");
|
||||
buffer.EndSample(k_DrawCombine);
|
||||
}
|
||||
|
||||
buffer.ReleaseTemporaryRT(ShaderIDs.s_WaveBuffer);
|
||||
@@ -372,16 +346,22 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
// Query collisions including only Animated Waves.
|
||||
// Requires copying the water level.
|
||||
Provider.UpdateQueries(_Water, CollisionLayer.AfterAnimatedWaves);
|
||||
// Guard not required, as Query already does this check before returning the
|
||||
// correct provider, thus nothing would be reqistered nor dispatched. But seems
|
||||
// right to do so anyhow.
|
||||
if (_CollisionLayers != CollisionLayers.Nothing)
|
||||
{
|
||||
Provider.UpdateQueries(_Water, CollisionLayer.AfterAnimatedWaves);
|
||||
}
|
||||
|
||||
// Transfer Dynamic Waves to Animated Waves.
|
||||
if (_CollisionLayers.HasFlag(CollisionLayers.DynamicWaves) && _Water._DynamicWavesLod.Enabled)
|
||||
{
|
||||
buffer.BeginSample("Combine");
|
||||
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, 8);
|
||||
var wrapper = new PropertyWrapperCompute(buffer, _CombineShader, 9);
|
||||
|
||||
wrapper.SetTexture(ShaderIDs.s_DynamicWavesTarget, ShaderIDs.s_DynamicWavesTarget);
|
||||
|
||||
@@ -392,22 +372,28 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy Dynamic Waves displacement into Animated Waves.
|
||||
{
|
||||
wrapper = new PropertyWrapperCompute(buffer, _CombineShader, 9);
|
||||
wrapper = new(buffer, _CombineShader, 10);
|
||||
wrapper.SetTexture(ShaderIDs.s_AnimatedWavesTarget, DataTexture);
|
||||
wrapper.SetTexture(ShaderIDs.s_DynamicWavesTarget, ShaderIDs.s_DynamicWavesTarget);
|
||||
wrapper.Dispatch(threadSize, threadSize, Slices);
|
||||
}
|
||||
|
||||
buffer.ReleaseTemporaryRT(ShaderIDs.s_DynamicWavesTarget);
|
||||
buffer.EndSample("Combine");
|
||||
buffer.EndSample(k_DrawCombine);
|
||||
|
||||
// Query collisions including Dynamic Waves.
|
||||
// Does not require copying the water level as they are added with zero alpha.
|
||||
_Water.CollisionProvider.UpdateQueries(_Water, CollisionLayer.AfterDynamicWaves);
|
||||
Provider.UpdateQueries(_Water, CollisionLayer.AfterDynamicWaves);
|
||||
}
|
||||
|
||||
if (_CollisionLayers.HasFlag(CollisionLayers.Displacement))
|
||||
@@ -429,7 +415,12 @@ namespace WaveHarmonic.Crest
|
||||
Shader.SetGlobalTexture(_TextureShaderID, DataTexture);
|
||||
}
|
||||
|
||||
buffer.EndSample(Name);
|
||||
buffer.EndSample(ID);
|
||||
}
|
||||
|
||||
internal override void AfterExecute()
|
||||
{
|
||||
Provider.SendReadBack(_Water, _CollisionLayers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
@@ -11,16 +11,15 @@ namespace WaveHarmonic.Crest
|
||||
/// <summary>
|
||||
/// The default state for clipping.
|
||||
/// </summary>
|
||||
[@GenerateDoc]
|
||||
public enum DefaultClippingState
|
||||
{
|
||||
/// <summary>
|
||||
/// By default, nothing is clipped. Use clip inputs to remove water.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.DefaultClippingState.NothingClipped"/>
|
||||
[Tooltip("By default, nothing is clipped. Use clip inputs to remove water.")]
|
||||
NothingClipped,
|
||||
|
||||
/// <summary>
|
||||
/// By default, everything is clipped. Use clip inputs to add water.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.DefaultClippingState.EverythingClipped"/>
|
||||
[Tooltip("By default, everything is clipped. Use clip inputs to add water.")]
|
||||
EverythingClipped,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
@@ -10,21 +10,19 @@ namespace WaveHarmonic.Crest
|
||||
/// <summary>
|
||||
/// The source of depth color.
|
||||
/// </summary>
|
||||
[@GenerateDoc]
|
||||
public enum ShorelineVolumeColorSource
|
||||
{
|
||||
/// <summary>
|
||||
/// No depth color.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.ShorelineVolumeColorSource.None"/>
|
||||
[Tooltip("No depth color.")]
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// Depth color based on water depth.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.ShorelineVolumeColorSource.Depth"/>
|
||||
[Tooltip("Depth color based on water depth.")]
|
||||
Depth,
|
||||
|
||||
/// <summary>
|
||||
/// Depth color based on shoreline distance.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.ShorelineVolumeColorSource.Distance"/>
|
||||
[Tooltip("Depth color based on shoreline distance.")]
|
||||
Distance,
|
||||
}
|
||||
|
||||
@@ -32,6 +30,7 @@ namespace WaveHarmonic.Crest
|
||||
/// Contains shared functionality for <see cref="AbsorptionLod"/> and <see cref="ScatteringLod"/>.
|
||||
/// </summary>
|
||||
[FilterEnum(nameof(_TextureFormatMode), Filtered.Mode.Exclude, (int)LodTextureFormatMode.Automatic)]
|
||||
[System.Serializable]
|
||||
public abstract partial class ColorLod : Lod
|
||||
{
|
||||
[@Space(10f)]
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Experimental.Rendering;
|
||||
using UnityEngine.Rendering;
|
||||
using WaveHarmonic.Crest.Internal;
|
||||
using WaveHarmonic.Crest.Utility;
|
||||
|
||||
namespace WaveHarmonic.Crest
|
||||
@@ -13,6 +15,13 @@ namespace WaveHarmonic.Crest
|
||||
[FilterEnum(nameof(_TextureFormatMode), Filtered.Mode.Exclude, (int)LodTextureFormatMode.Automatic)]
|
||||
public sealed partial class DepthLod : Lod<IDepthProvider>
|
||||
{
|
||||
[@Space(10)]
|
||||
|
||||
[Tooltip("Whether to include the terrain height automatically.\n\nThis will not include terrain details, nor will it produce a signed-distance field. There may also be a slight deviation due to differences in height data and terrain mesh. In these cases, please use the DepthProbe.")]
|
||||
[@GenerateAPI]
|
||||
[@DecoratedField, SerializeField]
|
||||
internal bool _IncludeTerrainHeight = true;
|
||||
|
||||
[Tooltip("Support signed distance field data generated from the depth probes.\n\nRequires a two component texture format.")]
|
||||
[@GenerateAPI(Setter.Custom)]
|
||||
[@DecoratedField, SerializeField]
|
||||
@@ -30,7 +39,6 @@ namespace WaveHarmonic.Crest
|
||||
internal override Color GizmoColor => s_GizmoColor;
|
||||
private protected override Color ClearColor => s_NullColor;
|
||||
private protected override bool NeedToReadWriteTextureData => true;
|
||||
internal override bool RunsInHeadless => true;
|
||||
|
||||
private protected override GraphicsFormat RequestedTextureFormat => _TextureFormatMode switch
|
||||
{
|
||||
@@ -89,6 +97,76 @@ namespace WaveHarmonic.Crest
|
||||
ReAllocate();
|
||||
}
|
||||
|
||||
#if d_Unity_Terrain
|
||||
TerrainDepthInput _TerrainDepthInput;
|
||||
|
||||
internal override void Enable()
|
||||
{
|
||||
base.Enable();
|
||||
|
||||
if (Enabled)
|
||||
{
|
||||
_TerrainDepthInput ??= new(this);
|
||||
Inputs.Add(_TerrainDepthInput.Queue, _TerrainDepthInput);
|
||||
}
|
||||
}
|
||||
|
||||
internal override void Disable()
|
||||
{
|
||||
base.Disable();
|
||||
|
||||
Inputs.Remove(_TerrainDepthInput);
|
||||
}
|
||||
|
||||
sealed class TerrainDepthInput : ILodInput
|
||||
{
|
||||
public bool Enabled => _DepthLod._IncludeTerrainHeight;
|
||||
public bool IsCompute => true;
|
||||
public int Queue => int.MinValue;
|
||||
public int Pass => -1;
|
||||
public Rect Rect => Rect.zero;
|
||||
public MonoBehaviour Component => null;
|
||||
public float Filter(WaterRenderer water, int slice) => 1f;
|
||||
|
||||
readonly DepthLod _DepthLod;
|
||||
readonly System.Collections.Generic.List<Terrain> _Terrains = new();
|
||||
|
||||
public TerrainDepthInput(DepthLod lod)
|
||||
{
|
||||
_DepthLod = lod;
|
||||
}
|
||||
|
||||
public void Draw(Lod lod, CommandBuffer buffer, RenderTargetIdentifier target, int pass = -1, float weight = 1, int slices = -1)
|
||||
{
|
||||
var resources = WaterResources.Instance;
|
||||
var wrapper = new PropertyWrapperCompute(buffer, resources.Compute._DepthTexture, 0);
|
||||
|
||||
var threads = lod.Resolution / k_ThreadGroupSize;
|
||||
|
||||
wrapper.SetTexture(Crest.ShaderIDs.s_Target, target);
|
||||
wrapper.SetVector(Crest.ShaderIDs.s_TextureRotation, new(0, 1));
|
||||
wrapper.SetBoolean(DepthLodInput.ShaderIDs.s_SDF, false);
|
||||
wrapper.SetKeyword(resources.Keywords.DepthTextureSDF, lod._Water._DepthLod._EnableSignedDistanceFields);
|
||||
|
||||
Terrain.GetActiveTerrains(_Terrains);
|
||||
foreach (var terrain in _Terrains)
|
||||
{
|
||||
var data = terrain.terrainData;
|
||||
if (data == null) continue;
|
||||
var size = data.size;
|
||||
var position = terrain.GetPosition();
|
||||
|
||||
wrapper.SetFloat(DepthLodInput.ShaderIDs.s_HeightOffset, position.y);
|
||||
wrapper.SetVector(Crest.ShaderIDs.s_Multiplier, new(size.y * 2f, 1, 1, 1));
|
||||
wrapper.SetVector(Crest.ShaderIDs.s_TexturePosition, position.XZ() + (size.XZ() * 0.5f));
|
||||
wrapper.SetVector(Crest.ShaderIDs.s_TextureSize, size.XZ());
|
||||
wrapper.SetTexture(Crest.ShaderIDs.s_Texture, data.heightmapTexture);
|
||||
wrapper.Dispatch(threads, threads, slices);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // d_Unity_Terrain
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[@OnChange]
|
||||
private protected override void OnChange(string propertyPath, object previousValue)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
@@ -41,7 +41,6 @@ namespace WaveHarmonic.Crest
|
||||
internal override string Name => "Dynamic Waves";
|
||||
internal override Color GizmoColor => s_GizmoColor;
|
||||
private protected override Color ClearColor => Color.black;
|
||||
internal override bool RunsInHeadless => true;
|
||||
private protected override ComputeShader SimulationShader => WaterResources.Instance.Compute._UpdateDynamicWaves;
|
||||
private protected override GraphicsFormat RequestedTextureFormat => _TextureFormatMode switch
|
||||
{
|
||||
@@ -88,7 +87,7 @@ namespace WaveHarmonic.Crest
|
||||
target.SetFloat(ShaderIDs.s_DisplaceClamp, Settings._DisplaceClamp);
|
||||
}
|
||||
|
||||
private protected override void SetAdditionalSimulationParameters<T>(T simMaterial)
|
||||
private protected override void SetAdditionalSimulationParameters(PropertyWrapperCompute simMaterial)
|
||||
{
|
||||
base.SetAdditionalSimulationParameters(simMaterial);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
@@ -21,7 +21,6 @@ namespace WaveHarmonic.Crest
|
||||
internal override Color GizmoColor => s_GizmoColor;
|
||||
private protected override Color ClearColor => Color.black;
|
||||
private protected override bool NeedToReadWriteTextureData => true;
|
||||
internal override bool RunsInHeadless => true;
|
||||
|
||||
private protected override GraphicsFormat RequestedTextureFormat => _TextureFormatMode switch
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
@@ -52,7 +52,7 @@ namespace WaveHarmonic.Crest
|
||||
_ => throw new System.NotImplementedException(),
|
||||
};
|
||||
|
||||
private protected override void SetAdditionalSimulationParameters<T>(T properties)
|
||||
private protected override void SetAdditionalSimulationParameters(PropertyWrapperCompute properties)
|
||||
{
|
||||
base.SetAdditionalSimulationParameters(properties);
|
||||
|
||||
|
||||
@@ -8,6 +8,32 @@ using WaveHarmonic.Crest.Utility;
|
||||
|
||||
namespace WaveHarmonic.Crest
|
||||
{
|
||||
[System.Serializable]
|
||||
partial class AbsorptionLod
|
||||
{
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
partial class AlbedoLod
|
||||
{
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
partial class AnimatedWavesLod
|
||||
{
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
partial class ClipLod
|
||||
{
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
partial class DepthLod
|
||||
{
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
partial class DynamicWavesLod
|
||||
{
|
||||
DynamicWavesLodSettings _DefaultSettings;
|
||||
@@ -36,6 +62,12 @@ namespace WaveHarmonic.Crest
|
||||
}
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
partial class FlowLod
|
||||
{
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
partial class FoamLod
|
||||
{
|
||||
FoamLodSettings _DefaultSettings;
|
||||
@@ -63,4 +95,19 @@ namespace WaveHarmonic.Crest
|
||||
Helpers.Destroy(_DefaultSettings);
|
||||
}
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
partial class LevelLod
|
||||
{
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
partial class ScatteringLod
|
||||
{
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
partial class ShadowLod
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
@@ -32,7 +32,7 @@ namespace WaveHarmonic.Crest
|
||||
[Tooltip("Whether the data is relative to the input height.\n\nUseful for procedural placement.")]
|
||||
[@GenerateAPI]
|
||||
[@DecoratedField, SerializeField]
|
||||
internal bool _Relative;
|
||||
internal bool _Relative = true;
|
||||
|
||||
[@Label("Copy Signed Distance Field")]
|
||||
[Tooltip("Whether to copy the signed distance field.")]
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.HighDefinition;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
using WaveHarmonic.Crest.Internal;
|
||||
using WaveHarmonic.Crest.Utility;
|
||||
|
||||
@@ -14,55 +11,51 @@ namespace WaveHarmonic.Crest
|
||||
/// <summary>
|
||||
/// <see cref="DepthProbe"/>'s update mode.
|
||||
/// </summary>
|
||||
[@GenerateDoc]
|
||||
public enum DepthProbeMode
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="DepthProbe"/> is updating in real-time, in accordance to <see cref="DepthProbeRefreshMode"/>.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.DepthProbeMode.RealTime"/>
|
||||
[Tooltip("Update in real-time in accordance to refresh mode.")]
|
||||
RealTime,
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="DepthProbe"/> is baked in the Editor.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.DepthProbeMode.Baked"/>
|
||||
[Tooltip("Baked in the editor.")]
|
||||
Baked,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// How the <see cref="DepthProbe"/> refreshes when using <see cref="DepthProbeMode.RealTime"/>.
|
||||
/// </summary>
|
||||
[@GenerateDoc]
|
||||
public enum DepthProbeRefreshMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Populates the <see cref="DepthProbe"/> in Start.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.DepthProbeRefreshMode.OnStart"/>
|
||||
[Tooltip("Populates the DepthProbe in Start.")]
|
||||
OnStart = 0,
|
||||
|
||||
// EveryFrame = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Requires manual updating via <see cref="DepthProbe.Populate"/>.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.DepthProbeRefreshMode.ViaScripting"/>
|
||||
[Tooltip("Requires manual updating via DepthProbe.Populate.")]
|
||||
ViaScripting = 2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// How a component is placed in the world.
|
||||
/// </summary>
|
||||
[@GenerateDoc]
|
||||
public enum Placement
|
||||
{
|
||||
/// <summary>
|
||||
/// The component is in a fixed position.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.Placement.Fixed"/>
|
||||
[Tooltip("The component is in a fixed position.")]
|
||||
Fixed,
|
||||
|
||||
/// <summary>
|
||||
/// The component follows the transform.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.Placement.Transform"/>
|
||||
[Tooltip("The component follows the transform.")]
|
||||
Transform,
|
||||
|
||||
/// <summary>
|
||||
/// The component follows the viewpoint.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.Placement.Viewpoint"/>
|
||||
[Tooltip("The component follows the viewpoint.")]
|
||||
Viewpoint,
|
||||
}
|
||||
|
||||
@@ -317,17 +310,6 @@ namespace WaveHarmonic.Crest
|
||||
public static readonly int s_VoronoiPingPong1 = Shader.PropertyToID("_Crest_VoronoiPingPong1");
|
||||
}
|
||||
|
||||
#if d_UnityHDRP
|
||||
static readonly List<FrameSettingsField> s_FrameSettingsFields = new()
|
||||
{
|
||||
FrameSettingsField.OpaqueObjects,
|
||||
FrameSettingsField.TransparentObjects,
|
||||
FrameSettingsField.TransparentPrepass,
|
||||
FrameSettingsField.TransparentPostpass,
|
||||
FrameSettingsField.AsyncCompute,
|
||||
};
|
||||
#endif
|
||||
|
||||
internal void Bind<T>(T wrapper) where T : IPropertyWrapper
|
||||
{
|
||||
wrapper.SetTexture(ShaderIDs.s_DepthProbe, Texture);
|
||||
@@ -446,39 +428,13 @@ namespace WaveHarmonic.Crest
|
||||
if (RenderPipelineHelper.IsUniversal)
|
||||
{
|
||||
#if d_UnityURP
|
||||
var additionalCameraData = _Camera.GetUniversalAdditionalCameraData();
|
||||
additionalCameraData.renderShadows = false;
|
||||
additionalCameraData.requiresColorTexture = false;
|
||||
additionalCameraData.requiresDepthTexture = false;
|
||||
additionalCameraData.renderPostProcessing = false;
|
||||
additionalCameraData.allowXRRendering = false;
|
||||
SetUpCameraURP();
|
||||
#endif
|
||||
}
|
||||
else if (RenderPipelineHelper.IsHighDefinition)
|
||||
{
|
||||
#if d_UnityHDRP
|
||||
var additionalCameraData = _Camera.gameObject.AddComponent<HDAdditionalCameraData>();
|
||||
|
||||
additionalCameraData.clearColorMode = HDAdditionalCameraData.ClearColorMode.Color;
|
||||
additionalCameraData.volumeLayerMask = 0;
|
||||
additionalCameraData.probeLayerMask = 0;
|
||||
additionalCameraData.xrRendering = false;
|
||||
|
||||
// Override camera frame settings to disable most of the expensive rendering for this camera.
|
||||
// Most importantly, disable custom passes and post-processing as third-party stuff might throw
|
||||
// errors because of this camera. Even with excluding a lot of HDRP features, it still does a
|
||||
// lit pass which is not cheap.
|
||||
additionalCameraData.customRenderingSettings = true;
|
||||
|
||||
foreach (FrameSettingsField frameSetting in System.Enum.GetValues(typeof(FrameSettingsField)))
|
||||
{
|
||||
if (!s_FrameSettingsFields.Contains(frameSetting))
|
||||
{
|
||||
// Enable override and then disable the feature.
|
||||
additionalCameraData.renderingPathCustomFrameSettingsOverrideMask.mask[(uint)frameSetting] = true;
|
||||
additionalCameraData.renderingPathCustomFrameSettings.SetEnabled(frameSetting, false);
|
||||
}
|
||||
}
|
||||
SetUpCameraHD();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -557,6 +513,10 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
OnBeforeRender?.Invoke(this);
|
||||
|
||||
_CommandBuffer ??= new();
|
||||
_CommandBuffer.Clear();
|
||||
_CommandBuffer.name = "Crest.DepthProbe";
|
||||
|
||||
#if UNITY_EDITOR
|
||||
try
|
||||
#endif
|
||||
@@ -566,6 +526,9 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
if (_FillHolesCaptureHeight > 0f)
|
||||
{
|
||||
Graphics.ExecuteCommandBuffer(_CommandBuffer);
|
||||
_CommandBuffer.Clear();
|
||||
|
||||
// Fill holes pass.
|
||||
RenderDepthIntoProbe(k_FillKernel, _CaptureRange.y + _FillHolesCaptureHeight);
|
||||
}
|
||||
@@ -588,10 +551,14 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
if (_GenerateSignedDistanceField)
|
||||
{
|
||||
_CommandBuffer.BeginSample("SDF");
|
||||
RenderSignedDistanceField(inverted: false);
|
||||
RenderSignedDistanceField(inverted: true);
|
||||
_CommandBuffer.EndSample("SDF");
|
||||
}
|
||||
|
||||
Graphics.ExecuteCommandBuffer(_CommandBuffer);
|
||||
|
||||
HashState(ref _RenderedStateHash);
|
||||
}
|
||||
|
||||
@@ -621,9 +588,17 @@ namespace WaveHarmonic.Crest
|
||||
backFaces = RenderTexture.GetTemporary(target.descriptor);
|
||||
_Camera.targetTexture = backFaces;
|
||||
|
||||
// Does not work for HDRP (handled elsewhere).
|
||||
var oldInvertCulling = GL.invertCulling;
|
||||
GL.invertCulling = true;
|
||||
|
||||
#if d_UnityHDRP
|
||||
if (RenderPipelineHelper.IsHighDefinition)
|
||||
{
|
||||
_HDAdditionalCameraData.invertFaceCulling = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Render scene, saving depths in depth buffer.
|
||||
#if d_UnityURP
|
||||
if (RenderPipelineHelper.IsUniversal)
|
||||
@@ -637,6 +612,14 @@ namespace WaveHarmonic.Crest
|
||||
}
|
||||
|
||||
_Camera.targetTexture = target;
|
||||
|
||||
#if d_UnityHDRP
|
||||
if (RenderPipelineHelper.IsHighDefinition)
|
||||
{
|
||||
_HDAdditionalCameraData.invertFaceCulling = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
GL.invertCulling = oldInvertCulling;
|
||||
}
|
||||
|
||||
@@ -652,7 +635,7 @@ namespace WaveHarmonic.Crest
|
||||
_Camera.Render();
|
||||
}
|
||||
|
||||
var wrapper = new PropertyWrapperComputeStandalone(WaterResources.Instance.Compute._RenderDepthProbe, kernel);
|
||||
var wrapper = new PropertyWrapperCompute(_CommandBuffer, WaterResources.Instance.Compute._RenderDepthProbe, kernel);
|
||||
|
||||
wrapper.SetFloat(ShaderIDs.s_HeightOffset, transform.position.y);
|
||||
|
||||
@@ -699,13 +682,12 @@ namespace WaveHarmonic.Crest
|
||||
return;
|
||||
}
|
||||
|
||||
var buffer = _CommandBuffer;
|
||||
|
||||
var cameraToWorldMatrix = _Camera.cameraToWorldMatrix;
|
||||
var projectionMatrix = _Camera.projectionMatrix;
|
||||
var projectionToWorldMatrix = cameraToWorldMatrix * projectionMatrix.inverse;
|
||||
|
||||
var buffer = _CommandBuffer ??= new();
|
||||
buffer.Clear();
|
||||
buffer.name = "Jump Flood";
|
||||
// Common uniforms.
|
||||
buffer.SetComputeFloatParam(shader, DepthLodInput.ShaderIDs.s_HeightOffset, transform.position.y);
|
||||
buffer.SetComputeIntParam(shader, Crest.ShaderIDs.s_TextureSize, _Resolution);
|
||||
@@ -802,7 +784,6 @@ namespace WaveHarmonic.Crest
|
||||
);
|
||||
}
|
||||
|
||||
Graphics.ExecuteCommandBuffer(buffer);
|
||||
buffer.ReleaseTemporaryRT(voronoiPingPong0);
|
||||
buffer.ReleaseTemporaryRT(voronoiPingPong1);
|
||||
}
|
||||
@@ -929,6 +910,7 @@ namespace WaveHarmonic.Crest
|
||||
wrapper.SetVector(Crest.ShaderIDs.s_TextureSize, _Probe.Scale);
|
||||
wrapper.SetVector(Crest.ShaderIDs.s_TexturePosition, position.XZ());
|
||||
wrapper.SetVector(Crest.ShaderIDs.s_TextureRotation, new Vector2(matrix.m20, matrix.m00).normalized);
|
||||
wrapper.SetVector(Crest.ShaderIDs.s_Multiplier, Vector4.one);
|
||||
wrapper.SetInteger(Crest.ShaderIDs.s_Blend, (int)LodInputBlend.Maximum);
|
||||
wrapper.SetTexture(Crest.ShaderIDs.s_Texture, _Probe.Texture);
|
||||
wrapper.SetTexture(Crest.ShaderIDs.s_Target, target);
|
||||
@@ -962,9 +944,9 @@ namespace WaveHarmonic.Crest
|
||||
Hash.AddBool(_EnableBackFaceInclusion, ref hash);
|
||||
Hash.AddInt(_AdditionalJumpFloodRounds, ref hash);
|
||||
Hash.AddBool(_GenerateSignedDistanceField, ref hash);
|
||||
Hash.AddObject(Position, ref hash);
|
||||
Hash.AddObject(Rotation, ref hash);
|
||||
Hash.AddObject(Scale, ref hash);
|
||||
Hash.AddObject(Managed ? Vector3.zero : Position, ref hash);
|
||||
Hash.AddObject(Managed ? Quaternion.identity : Rotation, ref hash);
|
||||
Hash.AddObject(Managed ? Vector2.zero : Scale, ref hash);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
@@ -992,7 +974,7 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (_Debug._ForceAlwaysUpdateDebug)
|
||||
if (_Debug._ForceAlwaysUpdateDebug && _Type != DepthProbeMode.Baked)
|
||||
{
|
||||
Populate();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
@@ -97,6 +97,7 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
/// <inheritdoc/>
|
||||
[ForLodInput(typeof(LevelLodInput), LodInputMode.Geometry)]
|
||||
[System.Serializable]
|
||||
public sealed class LevelGeometryLodInputData : GeometryLodInputData
|
||||
{
|
||||
private protected override Shader GeometryShader => WaterResources.Instance.Shaders._LevelGeometry;
|
||||
@@ -104,6 +105,7 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
/// <inheritdoc/>
|
||||
[ForLodInput(typeof(DepthLodInput), LodInputMode.Geometry)]
|
||||
[System.Serializable]
|
||||
public sealed class DepthGeometryLodInputData : GeometryLodInputData
|
||||
{
|
||||
private protected override Shader GeometryShader => WaterResources.Instance.Shaders._DepthGeometry;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using System;
|
||||
@@ -17,7 +17,7 @@ namespace WaveHarmonic.Crest
|
||||
/// <summary>
|
||||
/// Draw the input (the render target will be bound)
|
||||
/// </summary>
|
||||
public void Draw(Lod simulation, CommandBuffer buffer, RenderTargetIdentifier target, int pass = -1, float weight = 1f, int slice = -1);
|
||||
void Draw(Lod simulation, CommandBuffer buffer, RenderTargetIdentifier target, int pass = -1, float weight = 1f, int slice = -1);
|
||||
|
||||
float Filter(WaterRenderer water, int slice);
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace WaveHarmonic.Crest
|
||||
/// <summary>
|
||||
/// Data storage for an input, pertinent to the associated input mode.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public abstract class LodInputData
|
||||
{
|
||||
[SerializeField, HideInInspector]
|
||||
@@ -109,82 +110,70 @@ namespace WaveHarmonic.Crest
|
||||
/// <summary>
|
||||
/// Modes that inputs can use. Not all inputs support all modes. Refer to the UI.
|
||||
/// </summary>
|
||||
[@GenerateDoc]
|
||||
public enum LodInputMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Unset is the serialization default.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This will be replaced with the default mode automatically. Unset can also be
|
||||
/// used if something is invalid.
|
||||
/// </remarks>
|
||||
/// <inheritdoc cref="Generated.LodInputMode.Unset"/>
|
||||
[Tooltip("Unset is the serialization default.\n\nThis will be replaced with the default mode automatically. Unset can also be used if something is invalid.")]
|
||||
Unset = 0,
|
||||
/// <summary>
|
||||
/// Hand-painted data by the user. Currently unused.
|
||||
/// </summary>
|
||||
|
||||
/// <inheritdoc cref="Generated.LodInputMode.Paint"/>
|
||||
[Tooltip("Hand-painted data by the user.")]
|
||||
Paint,
|
||||
/// <summary>
|
||||
/// Driven by a user created spline.
|
||||
/// </summary>
|
||||
|
||||
/// <inheritdoc cref="Generated.LodInputMode.Spline"/>
|
||||
[Tooltip("Driven by a user created spline.")]
|
||||
Spline,
|
||||
/// <summary>
|
||||
/// Attached 'Renderer' (mesh, particle or other) used to drive data.
|
||||
/// </summary>
|
||||
|
||||
/// <inheritdoc cref="Generated.LodInputMode.Renderer"/>
|
||||
[Tooltip("Attached 'Renderer' (mesh, particle or other) used to drive data.")]
|
||||
Renderer,
|
||||
/// <summary>
|
||||
/// Driven by a mathematical primitive such as a cube or sphere.
|
||||
/// </summary>
|
||||
|
||||
/// <inheritdoc cref="Generated.LodInputMode.Primitive"/>
|
||||
[Tooltip("Driven by a mathematical primitive such as a cube or sphere.")]
|
||||
Primitive,
|
||||
/// <summary>
|
||||
/// Covers the entire water area.
|
||||
/// </summary>
|
||||
|
||||
/// <inheritdoc cref="Generated.LodInputMode.Global"/>
|
||||
[Tooltip("Covers the entire water area.")]
|
||||
Global,
|
||||
/// <summary>
|
||||
/// Data driven by a user provided texture.
|
||||
/// </summary>
|
||||
|
||||
/// <inheritdoc cref="Generated.LodInputMode.Texture"/>
|
||||
[Tooltip("Data driven by a user provided texture.")]
|
||||
Texture,
|
||||
/// <summary>
|
||||
/// Renders geometry using a default material.
|
||||
/// </summary>
|
||||
|
||||
/// <inheritdoc cref="Generated.LodInputMode.Geometry"/>
|
||||
[Tooltip("Renders geometry using a default material.")]
|
||||
Geometry,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Blend presets for inputs.
|
||||
/// </summary>
|
||||
[@GenerateDoc]
|
||||
public enum LodInputBlend
|
||||
{
|
||||
/// <summary>
|
||||
/// No blending. Overwrites.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.LodInputBlend.Off"/>
|
||||
[Tooltip("No blending. Overwrites.")]
|
||||
Off,
|
||||
|
||||
/// <summary>
|
||||
/// Additive blending.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.LodInputBlend.Additive"/>
|
||||
[Tooltip("Additive blending.")]
|
||||
Additive,
|
||||
|
||||
/// <summary>
|
||||
/// Takes the minimum value.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.LodInputBlend.Minimum"/>
|
||||
[Tooltip("Takes the minimum value.")]
|
||||
Minimum,
|
||||
|
||||
/// <summary>
|
||||
/// Takes the maximum value.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.LodInputBlend.Maximum"/>
|
||||
[Tooltip("Takes the maximum value.")]
|
||||
Maximum,
|
||||
|
||||
/// <summary>
|
||||
/// Applies the inverse weight to the target.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Basically overwrites what is already in the simulation.
|
||||
/// </remarks>
|
||||
/// <inheritdoc cref="Generated.LodInputBlend.Alpha"/>
|
||||
[Tooltip("Applies the inverse weight to the target.\n\nBasically overwrites what is already in the simulation.")]
|
||||
Alpha,
|
||||
|
||||
/// <summary>
|
||||
/// Same as alpha except anything above zero will overwrite rather than blend.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.LodInputBlend.AlphaClip"/>
|
||||
[Tooltip("Same as alpha except anything above zero will overwrite rather than blend.")]
|
||||
AlphaClip,
|
||||
}
|
||||
|
||||
@@ -192,21 +181,19 @@ namespace WaveHarmonic.Crest
|
||||
/// Primitive shapes.
|
||||
/// </summary>
|
||||
// Have this match UnityEngine.PrimitiveType.
|
||||
[@GenerateDoc]
|
||||
public enum LodInputPrimitive
|
||||
{
|
||||
/// <summary>
|
||||
/// Spheroid.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.LodInputPrimitive.Sphere"/>
|
||||
[Tooltip("Spheroid.")]
|
||||
Sphere = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Cuboid.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.LodInputPrimitive.Cube"/>
|
||||
[Tooltip("Cuboid.")]
|
||||
Cube = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Quad.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.LodInputPrimitive.Quad"/>
|
||||
[Tooltip("Quad.")]
|
||||
Quad = 5,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ef4f3d3c2ad88274294da9c9be0143e7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,54 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
#if d_UnityHDRP
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Rendering.HighDefinition;
|
||||
|
||||
namespace WaveHarmonic.Crest
|
||||
{
|
||||
partial class DepthProbe
|
||||
{
|
||||
static readonly List<FrameSettingsField> s_FrameSettingsFields = new()
|
||||
{
|
||||
FrameSettingsField.OpaqueObjects,
|
||||
FrameSettingsField.TransparentObjects,
|
||||
FrameSettingsField.TransparentPrepass,
|
||||
FrameSettingsField.TransparentPostpass,
|
||||
FrameSettingsField.AsyncCompute,
|
||||
};
|
||||
|
||||
HDAdditionalCameraData _HDAdditionalCameraData;
|
||||
|
||||
void SetUpCameraHD()
|
||||
{
|
||||
var additionalCameraData = _Camera.gameObject.AddComponent<HDAdditionalCameraData>();
|
||||
|
||||
additionalCameraData.clearColorMode = HDAdditionalCameraData.ClearColorMode.Color;
|
||||
additionalCameraData.volumeLayerMask = 0;
|
||||
additionalCameraData.probeLayerMask = 0;
|
||||
additionalCameraData.xrRendering = false;
|
||||
|
||||
// Override camera frame settings to disable most of the expensive rendering for this camera.
|
||||
// Most importantly, disable custom passes and post-processing as third-party stuff might throw
|
||||
// errors because of this camera. Even with excluding a lot of HDRP features, it still does a
|
||||
// lit pass which is not cheap.
|
||||
additionalCameraData.customRenderingSettings = true;
|
||||
|
||||
foreach (FrameSettingsField frameSetting in System.Enum.GetValues(typeof(FrameSettingsField)))
|
||||
{
|
||||
if (!s_FrameSettingsFields.Contains(frameSetting))
|
||||
{
|
||||
// Enable override and then disable the feature.
|
||||
additionalCameraData.renderingPathCustomFrameSettingsOverrideMask.mask[(uint)frameSetting] = true;
|
||||
additionalCameraData.renderingPathCustomFrameSettings.SetEnabled(frameSetting, false);
|
||||
}
|
||||
}
|
||||
|
||||
_HDAdditionalCameraData = additionalCameraData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // d_UnityHDRP
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93b38270a78f94e43bfbbe01ef2e351b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 300
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,24 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
#if d_UnityURP
|
||||
|
||||
using UnityEngine.Rendering.Universal;
|
||||
|
||||
namespace WaveHarmonic.Crest
|
||||
{
|
||||
partial class DepthProbe
|
||||
{
|
||||
void SetUpCameraURP()
|
||||
{
|
||||
var additionalCameraData = _Camera.GetUniversalAdditionalCameraData();
|
||||
additionalCameraData.renderShadows = false;
|
||||
additionalCameraData.requiresColorTexture = false;
|
||||
additionalCameraData.requiresDepthTexture = false;
|
||||
additionalCameraData.renderPostProcessing = false;
|
||||
additionalCameraData.allowXRRendering = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // d_UnityURP
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c3d572236539a490aaddc647129ad141
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 300
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -11,6 +11,7 @@ namespace WaveHarmonic.Crest
|
||||
/// <summary>
|
||||
/// Data storage for for the Renderer input mode.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public abstract partial class RendererLodInputData : LodInputData
|
||||
{
|
||||
[Tooltip("The renderer to use for this input.\n\nCan be anything that inherits from <i>Renderer</i> like <i>MeshRenderer</i>, <i>TrailRenderer</i> etc.")]
|
||||
@@ -47,12 +48,6 @@ namespace WaveHarmonic.Crest
|
||||
#pragma warning restore 414
|
||||
|
||||
|
||||
static class ShaderIDs
|
||||
{
|
||||
public static readonly int s_Time = Shader.PropertyToID("_Time");
|
||||
}
|
||||
|
||||
|
||||
// Some renderers require multiple materials like particles with trails.
|
||||
// We pass this to GetSharedMaterials to avoid allocations.
|
||||
internal List<Material> _Materials = new();
|
||||
@@ -169,35 +164,31 @@ namespace WaveHarmonic.Crest
|
||||
}
|
||||
#endif
|
||||
|
||||
var pass = _ShaderPassIndex;
|
||||
// BIRP/URP SG first pass is the right one.
|
||||
// HDRP SG does not support matrix override, but users can just use BIRP instead.
|
||||
var pass = 0;
|
||||
|
||||
if (ShapeWaves.s_RenderPassOverride > -1)
|
||||
{
|
||||
// Needs to use a second pass to disable blending.
|
||||
pass = ShapeWaves.s_RenderPassOverride;
|
||||
}
|
||||
else if (!_OverrideShaderPass)
|
||||
else if (_OverrideShaderPass)
|
||||
{
|
||||
// BIRP/URP SG first pass is the right one.
|
||||
pass = 0;
|
||||
|
||||
// Support HDRP SG. It will always have more than one pass.
|
||||
if (RenderPipelineHelper.IsHighDefinition && material.shader.passCount > 1)
|
||||
{
|
||||
var sgPass = material.FindPass("ForwardOnly");
|
||||
if (sgPass > -1) pass = sgPass;
|
||||
}
|
||||
pass = _ShaderPassIndex;
|
||||
}
|
||||
else if (_ShaderPassIndex > material.shader.passCount - 1)
|
||||
|
||||
if (pass > material.shader.passCount - 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Time is not set for us for some reason… Use Time.timeSinceLevelLoad as per:
|
||||
// https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html
|
||||
if (RenderPipelineHelper.IsLegacy)
|
||||
if (RenderPipelineHelper.IsLegacy || RenderPipelineHelper.IsHighDefinition)
|
||||
{
|
||||
_Renderer.GetPropertyBlock(_MaterialPropertyBlock);
|
||||
_MaterialPropertyBlock.SetVector(ShaderIDs.s_Time, new
|
||||
_MaterialPropertyBlock.SetVector(ShaderIDs.Unity.s_Time, new
|
||||
(
|
||||
Time.timeSinceLevelLoad / 20,
|
||||
Time.timeSinceLevelLoad,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
@@ -14,14 +14,21 @@ namespace WaveHarmonic.Crest
|
||||
{
|
||||
// Waves
|
||||
|
||||
[Tooltip("How turbulent/chaotic the waves are.")]
|
||||
[@Range(0, 1, order = -3)]
|
||||
[Tooltip("Whether to use the wind turbulence on this component rather than the global wind turbulence.\n\nGlobal wind turbulence comes from the Water Renderer component.")]
|
||||
[@GenerateAPI]
|
||||
[@InlineToggle(order = -3), SerializeField]
|
||||
bool _OverrideGlobalWindTurbulence;
|
||||
|
||||
[Tooltip("How turbulent/chaotic the waves are.")]
|
||||
[@Predicated(nameof(_OverrideGlobalWindTurbulence), hide: true)]
|
||||
[@ShowComputedProperty(nameof(WindTurbulence))]
|
||||
[@Range(0, 1, order = -4)]
|
||||
[@GenerateAPI(Getter.Custom)]
|
||||
[SerializeField]
|
||||
float _WindTurbulence = 0.145f;
|
||||
|
||||
[Tooltip("How aligned the waves are with wind.")]
|
||||
[@Range(0, 1, order = -4)]
|
||||
[@Range(0, 1, order = -5)]
|
||||
[@GenerateAPI]
|
||||
[SerializeField]
|
||||
float _WindAlignment;
|
||||
@@ -51,23 +58,39 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
[@Heading("Collision Data Baking")]
|
||||
|
||||
#if !d_WaveHarmonic_Crest_CPUQueries
|
||||
[HideInInspector]
|
||||
#endif
|
||||
|
||||
[Tooltip("Enable running this FFT with baked data.\n\nThis makes the FFT periodic (repeating in time).")]
|
||||
[@Predicated(nameof(_Mode), inverted: true, nameof(LodInputMode.Global), hide: true)]
|
||||
[@DecoratedField, SerializeField]
|
||||
internal bool _EnableBakedCollision = false;
|
||||
|
||||
#if !d_WaveHarmonic_Crest_CPUQueries
|
||||
[HideInInspector]
|
||||
#endif
|
||||
|
||||
[Tooltip("Frames per second of baked data.\n\nLarger values may help the collision track the surface closely at the cost of more frames and increase baked data size.")]
|
||||
[@Predicated(nameof(_EnableBakedCollision))]
|
||||
[@Predicated(nameof(_Mode), inverted: true, nameof(LodInputMode.Global), hide: true)]
|
||||
[@DecoratedField, SerializeField]
|
||||
internal int _TimeResolution = 4;
|
||||
|
||||
#if !d_WaveHarmonic_Crest_CPUQueries
|
||||
[HideInInspector]
|
||||
#endif
|
||||
|
||||
[Tooltip("Smallest wavelength required in collision.\n\nTo preview the effect of this, disable power sliders in spectrum for smaller values than this number. Smaller values require more resolution and increase baked data size.")]
|
||||
[@Predicated(nameof(_EnableBakedCollision))]
|
||||
[@Predicated(nameof(_Mode), inverted: true, nameof(LodInputMode.Global), hide: true)]
|
||||
[@DecoratedField, SerializeField]
|
||||
internal float _SmallestWavelengthRequired = 2f;
|
||||
|
||||
#if !d_WaveHarmonic_Crest_CPUQueries
|
||||
[HideInInspector]
|
||||
#endif
|
||||
|
||||
[Tooltip("FFT waves will loop with a period of this many seconds.\n\nSmaller values decrease data size but can make waves visibly repetitive.")]
|
||||
[@Predicated(nameof(_EnableBakedCollision))]
|
||||
[@Predicated(nameof(_Mode), inverted: true, nameof(LodInputMode.Global), hide: true)]
|
||||
@@ -75,21 +98,28 @@ namespace WaveHarmonic.Crest
|
||||
[SerializeField]
|
||||
internal float _BakedTimeLoopLength = 32f;
|
||||
|
||||
internal float LoopPeriod => _EnableBakedCollision ? _BakedTimeLoopLength : _TimeLoopLength;
|
||||
internal float LoopPeriod =>
|
||||
#if d_WaveHarmonic_Crest_CPUQueries
|
||||
_EnableBakedCollision ? _BakedTimeLoopLength :
|
||||
#endif
|
||||
_TimeLoopLength;
|
||||
|
||||
private protected override int MinimumResolution => 16;
|
||||
private protected override int MaximumResolution => int.MaxValue;
|
||||
|
||||
FFTCompute _FFTCompute;
|
||||
|
||||
FFTCompute.Parameters _OldFFTParameters;
|
||||
internal FFTCompute.Parameters FFTParameters => new
|
||||
internal FFTCompute.Parameters GetFFTParameters(float gravity) => new
|
||||
(
|
||||
_ActiveSpectrum,
|
||||
Resolution,
|
||||
_TimeLoopLength,
|
||||
WindSpeedMPS,
|
||||
WindDirRadForFFT,
|
||||
_WindTurbulence,
|
||||
_WindAlignment
|
||||
WindTurbulence,
|
||||
_WindAlignment,
|
||||
gravity
|
||||
);
|
||||
|
||||
private protected override void OnUpdate(WaterRenderer water)
|
||||
@@ -103,7 +133,7 @@ namespace WaveHarmonic.Crest
|
||||
ReportMaxDisplacement(water);
|
||||
|
||||
// If geometry is being used, the water input shader will rotate the waves to align to geo
|
||||
var parameters = FFTParameters;
|
||||
var parameters = GetFFTParameters(water.Gravity);
|
||||
|
||||
// Don't create tons of generators when values are varying. Notify so that existing generators may be adapted.
|
||||
if (parameters.GetHashCode() != _OldFFTParameters.GetHashCode())
|
||||
@@ -111,6 +141,10 @@ namespace WaveHarmonic.Crest
|
||||
FFTCompute.OnGenerationDataUpdated(_OldFFTParameters, parameters);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
_FFTCompute = FFTCompute.GetInstance(parameters);
|
||||
#endif
|
||||
|
||||
_OldFFTParameters = parameters;
|
||||
}
|
||||
|
||||
@@ -118,14 +152,22 @@ namespace WaveHarmonic.Crest
|
||||
{
|
||||
if (_LastGenerateFrameCount != Time.frameCount)
|
||||
{
|
||||
// Parameters will unlikely change as our Update is called in LateUpdate with Draw
|
||||
// not too far after.
|
||||
var parameters = GetFFTParameters(lod.Water.Gravity);
|
||||
|
||||
_WaveBuffers = FFTCompute.GenerateDisplacements
|
||||
(
|
||||
buffer,
|
||||
lod.Water.CurrentTime,
|
||||
FFTParameters,
|
||||
parameters,
|
||||
UpdateDataEachFrame
|
||||
);
|
||||
|
||||
#if UNITY_EDITOR
|
||||
_FFTCompute = FFTCompute.GetInstance(parameters);
|
||||
#endif
|
||||
|
||||
_LastGenerateFrameCount = Time.frameCount;
|
||||
}
|
||||
|
||||
@@ -157,11 +199,6 @@ namespace WaveHarmonic.Crest
|
||||
}
|
||||
}
|
||||
|
||||
private protected override void DestroySharedResources()
|
||||
{
|
||||
FFTCompute.CleanUpAll();
|
||||
}
|
||||
|
||||
float WindDirRadForFFT
|
||||
{
|
||||
get
|
||||
@@ -172,36 +209,64 @@ namespace WaveHarmonic.Crest
|
||||
return 0f;
|
||||
}
|
||||
|
||||
return _WaveDirectionHeadingAngle * Mathf.Deg2Rad;
|
||||
return WaveDirectionHeadingAngle * Mathf.Deg2Rad;
|
||||
}
|
||||
}
|
||||
|
||||
float GetWindTurbulence()
|
||||
{
|
||||
return _OverrideGlobalWindTurbulence || WaterRenderer.Instance == null ? _WindTurbulence : WaterRenderer.Instance.WindTurbulence;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
void OnGUI()
|
||||
{
|
||||
if (_DrawSlicesInEditor)
|
||||
{
|
||||
FFTCompute.GetInstance(FFTParameters)?.OnGUI();
|
||||
_FFTCompute?.OnGUI();
|
||||
}
|
||||
}
|
||||
|
||||
internal FFTCompute GetFFTComputeInstance()
|
||||
{
|
||||
return FFTCompute.GetInstance(FFTParameters);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
partial class ShapeFFT
|
||||
{
|
||||
static int s_InstanceCount;
|
||||
|
||||
private protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
s_InstanceCount++;
|
||||
}
|
||||
|
||||
private protected override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
|
||||
if (--s_InstanceCount <= 0)
|
||||
{
|
||||
FFTCompute.CleanUpAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
partial class ShapeFFT : ISerializationCallbackReceiver
|
||||
{
|
||||
[SerializeField, HideInInspector]
|
||||
#pragma warning disable 414
|
||||
int _Version = 1;
|
||||
int _Version = 2;
|
||||
#pragma warning restore 414
|
||||
|
||||
void ISerializationCallbackReceiver.OnAfterDeserialize()
|
||||
{
|
||||
_Version = MigrateV1(_Version);
|
||||
|
||||
if (_Version < 2)
|
||||
{
|
||||
_OverrideGlobalWindTurbulence = true;
|
||||
}
|
||||
|
||||
_Version = MigrateV2(_Version);
|
||||
}
|
||||
|
||||
void ISerializationCallbackReceiver.OnBeforeSerialize()
|
||||
@@ -209,4 +274,19 @@ namespace WaveHarmonic.Crest
|
||||
// Empty.
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
partial class ShapeFFT
|
||||
{
|
||||
private protected override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
if (_Mode != LodInputMode.Global)
|
||||
{
|
||||
_OverrideGlobalWindTurbulence = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -17,9 +17,17 @@ namespace WaveHarmonic.Crest
|
||||
{
|
||||
// Waves
|
||||
|
||||
[Tooltip("The weight of the opposing, second pair of Gerstner waves.\n\nEach Gerstner wave is actually a pair of waves travelling in opposite directions (similar to FFT). This weight is applied to the wave travelling in against-wind direction. Set to zero to obtain simple single waves which are useful for shorelines waves.")]
|
||||
[@Range(0f, 1f, order = -3)]
|
||||
[@Space(10)]
|
||||
|
||||
[Tooltip("Use a swell spectrum as the default.\n\nUses a swell spectrum as default (when none is assigned), and disabled reverse waves.")]
|
||||
[@GenerateAPI]
|
||||
[@DecoratedField(order = -3), SerializeField]
|
||||
bool _Swell = true;
|
||||
|
||||
[Tooltip("The weight of the opposing, second pair of Gerstner waves.\n\nEach Gerstner wave is actually a pair of waves travelling in opposite directions (similar to FFT). This weight is applied to the wave travelling in against-wind direction. Set to zero to obtain simple single waves which are useful for shorelines waves.")]
|
||||
[Predicated(nameof(_Swell), inverted: true)]
|
||||
[@Range(0f, 1f, order = -4)]
|
||||
[@GenerateAPI(Getter.Custom)]
|
||||
[SerializeField]
|
||||
float _ReverseWaveWeight = 0.5f;
|
||||
|
||||
@@ -37,6 +45,11 @@ namespace WaveHarmonic.Crest
|
||||
[SerializeField]
|
||||
int _RandomSeed = 0;
|
||||
|
||||
[Tooltip("Prevent data arrays from being written to so one can provide their own.")]
|
||||
[@GenerateAPI]
|
||||
[SerializeField]
|
||||
bool _ManualGeneration;
|
||||
|
||||
private protected override int MinimumResolution => 8;
|
||||
private protected override int MaximumResolution => 64;
|
||||
|
||||
@@ -45,12 +58,39 @@ namespace WaveHarmonic.Crest
|
||||
const int k_MaximumWaveComponents = 1024;
|
||||
|
||||
// Data for all components
|
||||
float[] _Wavelengths;
|
||||
float[] _Amplitudes;
|
||||
|
||||
/// <summary>
|
||||
/// Wavelengths. Requires Manual Generation to be enabled.
|
||||
/// </summary>
|
||||
[System.NonSerialized]
|
||||
public float[] _Wavelengths;
|
||||
|
||||
/// <summary>
|
||||
/// Amplitudes. Requires Manual Generation to be enabled.
|
||||
/// </summary>
|
||||
[System.NonSerialized]
|
||||
public float[] _Amplitudes;
|
||||
|
||||
/// <summary>
|
||||
/// Powers. Requires Manual Generation to be enabled.
|
||||
/// </summary>
|
||||
[System.NonSerialized]
|
||||
public float[] _Powers;
|
||||
|
||||
/// <summary>
|
||||
/// Angles. Requires Manual Generation to be enabled.
|
||||
/// </summary>
|
||||
[System.NonSerialized]
|
||||
public float[] _AngleDegrees;
|
||||
|
||||
/// <summary>
|
||||
/// Phases. Requires Manual Generation to be enabled.
|
||||
/// </summary>
|
||||
[System.NonSerialized]
|
||||
public float[] _Phases;
|
||||
|
||||
// Reverse.
|
||||
float[] _Amplitudes2;
|
||||
float[] _Powers;
|
||||
float[] _AngleDegrees;
|
||||
float[] _Phases;
|
||||
float[] _Phases2;
|
||||
|
||||
struct GerstnerCascadeParams
|
||||
@@ -82,6 +122,33 @@ namespace WaveHarmonic.Crest
|
||||
ComputeShader _ShaderGerstner;
|
||||
int _KernelGerstner = -1;
|
||||
|
||||
private protected override WaveSpectrum DefaultSpectrum => _Swell ? SwellSpectrum : WindSpectrum;
|
||||
static WaveSpectrum s_SwellSpectrum;
|
||||
static WaveSpectrum SwellSpectrum
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_SwellSpectrum == null)
|
||||
{
|
||||
s_SwellSpectrum = ScriptableObject.CreateInstance<WaveSpectrum>();
|
||||
s_SwellSpectrum.name = "Swell Waves (auto)";
|
||||
s_SwellSpectrum.hideFlags = HideFlags.DontSave | HideFlags.NotEditable;
|
||||
s_SwellSpectrum._PowerDisabled[0] = true;
|
||||
s_SwellSpectrum._PowerDisabled[1] = true;
|
||||
s_SwellSpectrum._PowerDisabled[2] = true;
|
||||
s_SwellSpectrum._PowerDisabled[3] = true;
|
||||
s_SwellSpectrum._PowerDisabled[4] = true;
|
||||
s_SwellSpectrum._PowerDisabled[5] = true;
|
||||
s_SwellSpectrum._PowerDisabled[6] = true;
|
||||
s_SwellSpectrum._PowerDisabled[7] = true;
|
||||
s_SwellSpectrum._WaveDirectionVariance = 15f;
|
||||
s_SwellSpectrum._Chop = 1.3f;
|
||||
}
|
||||
|
||||
return s_SwellSpectrum;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static new class ShaderIDs
|
||||
{
|
||||
@@ -103,6 +170,11 @@ namespace WaveHarmonic.Crest
|
||||
s_Instances.Clear();
|
||||
}
|
||||
|
||||
float GetReverseWaveWeight()
|
||||
{
|
||||
return _Swell ? 0f : _ReverseWaveWeight;
|
||||
}
|
||||
|
||||
void InitData()
|
||||
{
|
||||
if (_WaveBuffers == null)
|
||||
@@ -167,7 +239,7 @@ namespace WaveHarmonic.Crest
|
||||
{
|
||||
UpdateGenerateWaves(buffer);
|
||||
// Above changes the render target. Change it back if necessary.
|
||||
if (!IsCompute) buffer.SetRenderTarget(target, 0, CubemapFace.Unknown, slice);
|
||||
if (!IsCompute) CoreUtils.SetRenderTarget(buffer, target, depthSlice: slice);
|
||||
}
|
||||
|
||||
_LastGenerateFrameCount = Time.frameCount;
|
||||
@@ -196,6 +268,16 @@ namespace WaveHarmonic.Crest
|
||||
var outputIdx = 0;
|
||||
_CascadeParameters[0]._StartIndex = 0;
|
||||
|
||||
if (_ManualGeneration)
|
||||
{
|
||||
for (var i = 0; i < _WaveData.Length; i++)
|
||||
{
|
||||
_WaveData[i]._Phase2 = Vector4.zero;
|
||||
_WaveData[i]._Amplitude2 = Vector4.zero;
|
||||
_WaveData[i]._ChopAmplitude2 = Vector4.zero;
|
||||
}
|
||||
}
|
||||
|
||||
// Seek forward to first wavelength that is big enough to render into current cascades
|
||||
var minWl = MinWavelength(cascadeIdx);
|
||||
while (componentIdx < _Wavelengths.Length && _Wavelengths[componentIdx] < minWl)
|
||||
@@ -230,10 +312,13 @@ namespace WaveHarmonic.Crest
|
||||
_WaveData[vi]._WaveDirectionZ[ei] = 0f;
|
||||
_WaveData[vi]._Omega[ei] = 0f;
|
||||
_WaveData[vi]._Phase[ei] = 0f;
|
||||
_WaveData[vi]._Phase2[ei] = 0f;
|
||||
_WaveData[vi]._ChopAmplitude[ei] = 0f;
|
||||
_WaveData[vi]._Amplitude2[ei] = 0f;
|
||||
_WaveData[vi]._ChopAmplitude2[ei] = 0f;
|
||||
if (!_ManualGeneration)
|
||||
{
|
||||
_WaveData[vi]._Phase2[ei] = 0f;
|
||||
_WaveData[vi]._Amplitude2[ei] = 0f;
|
||||
_WaveData[vi]._ChopAmplitude2[ei] = 0f;
|
||||
}
|
||||
ei = (ei + 1) % 4;
|
||||
outputIdx++;
|
||||
}
|
||||
@@ -254,11 +339,15 @@ namespace WaveHarmonic.Crest
|
||||
var ei = outputIdx - vi * 4;
|
||||
|
||||
_WaveData[vi]._Amplitude[ei] = _Amplitudes[componentIdx];
|
||||
_WaveData[vi]._Amplitude2[ei] = _Amplitudes2[componentIdx];
|
||||
|
||||
var chopScale = _ActiveSpectrum._ChopScales[componentIdx / _ComponentsPerOctave];
|
||||
_WaveData[vi]._ChopAmplitude[ei] = -chopScale * _ActiveSpectrum._Chop * _Amplitudes[componentIdx];
|
||||
_WaveData[vi]._ChopAmplitude2[ei] = -chopScale * _ActiveSpectrum._Chop * _Amplitudes2[componentIdx];
|
||||
|
||||
if (!_ManualGeneration)
|
||||
{
|
||||
_WaveData[vi]._Amplitude2[ei] = _Amplitudes2[componentIdx];
|
||||
_WaveData[vi]._ChopAmplitude2[ei] = -chopScale * _ActiveSpectrum._Chop * _Amplitudes2[componentIdx];
|
||||
}
|
||||
|
||||
var angle = Mathf.Deg2Rad * _AngleDegrees[componentIdx];
|
||||
var dx = Mathf.Cos(angle);
|
||||
@@ -295,7 +384,11 @@ namespace WaveHarmonic.Crest
|
||||
// Repeat every 2pi to keep angle bounded - helps precision on 16bit platforms
|
||||
_WaveData[vi]._Omega[ei] = k * c;
|
||||
_WaveData[vi]._Phase[ei] = Mathf.Repeat(_Phases[componentIdx], Mathf.PI * 2f);
|
||||
_WaveData[vi]._Phase2[ei] = Mathf.Repeat(_Phases2[componentIdx], Mathf.PI * 2f);
|
||||
|
||||
if (!_ManualGeneration)
|
||||
{
|
||||
_WaveData[vi]._Phase2[ei] = Mathf.Repeat(_Phases2[componentIdx], Mathf.PI * 2f);
|
||||
}
|
||||
|
||||
outputIdx++;
|
||||
}
|
||||
@@ -316,10 +409,13 @@ namespace WaveHarmonic.Crest
|
||||
_WaveData[vi]._WaveDirectionZ[ei] = 0f;
|
||||
_WaveData[vi]._Omega[ei] = 0f;
|
||||
_WaveData[vi]._Phase[ei] = 0f;
|
||||
_WaveData[vi]._Phase2[ei] = 0f;
|
||||
_WaveData[vi]._ChopAmplitude[ei] = 0f;
|
||||
_WaveData[vi]._Amplitude2[ei] = 0f;
|
||||
_WaveData[vi]._ChopAmplitude2[ei] = 0f;
|
||||
if (!_ManualGeneration)
|
||||
{
|
||||
_WaveData[vi]._Phase2[ei] = 0f;
|
||||
_WaveData[vi]._Amplitude2[ei] = 0f;
|
||||
_WaveData[vi]._ChopAmplitude2[ei] = 0f;
|
||||
}
|
||||
ei = (ei + 1) % 4;
|
||||
outputIdx++;
|
||||
}
|
||||
@@ -340,8 +436,7 @@ namespace WaveHarmonic.Crest
|
||||
void UpdateGenerateWaves(CommandBuffer buf)
|
||||
{
|
||||
// Clear existing waves or they could get copied.
|
||||
buf.SetRenderTarget(_WaveBuffers, 0, CubemapFace.Unknown, -1);
|
||||
buf.ClearRenderTarget(RTClearFlags.Color, Color.black, 0, 0);
|
||||
CoreUtils.SetRenderTarget(buf, _WaveBuffers, ClearFlag.Color);
|
||||
buf.SetComputeFloatParam(_ShaderGerstner, ShaderIDs.s_TextureRes, _WaveBuffers.width);
|
||||
buf.SetComputeIntParam(_ShaderGerstner, ShaderIDs.s_FirstCascadeIndex, _FirstCascade);
|
||||
buf.SetComputeBufferParam(_ShaderGerstner, _KernelGerstner, ShaderIDs.s_CascadeParams, _BufferCascadeParameters);
|
||||
@@ -358,13 +453,23 @@ namespace WaveHarmonic.Crest
|
||||
/// <param name="windSpeed">Wind speed in m/s</param>
|
||||
void UpdateWaveData(WaterRenderer water, float windSpeed)
|
||||
{
|
||||
if (_ManualGeneration)
|
||||
{
|
||||
if (_Wavelengths != null)
|
||||
{
|
||||
SliceUpWaves(water, windSpeed);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Set random seed to get repeatable results
|
||||
var randomStateBkp = Random.state;
|
||||
Random.InitState(_RandomSeed);
|
||||
|
||||
_ActiveSpectrum.GenerateWaveData(_ComponentsPerOctave, ref _Wavelengths, ref _AngleDegrees);
|
||||
|
||||
UpdateAmplitudes();
|
||||
UpdateAmplitudes(water);
|
||||
|
||||
// Won't run every time so put last in the random sequence
|
||||
if (_Phases == null || _Phases.Length != _Wavelengths.Length || _Phases2 == null || _Phases2.Length != _Wavelengths.Length)
|
||||
@@ -377,7 +482,7 @@ namespace WaveHarmonic.Crest
|
||||
SliceUpWaves(water, windSpeed);
|
||||
}
|
||||
|
||||
void UpdateAmplitudes()
|
||||
void UpdateAmplitudes(WaterRenderer water)
|
||||
{
|
||||
if (_Amplitudes == null || _Amplitudes.Length != _Wavelengths.Length)
|
||||
{
|
||||
@@ -396,9 +501,9 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
for (var i = 0; i < _Wavelengths.Length; i++)
|
||||
{
|
||||
var amp = _ActiveSpectrum.GetAmplitude(_Wavelengths[i], _ComponentsPerOctave, windSpeed, out _Powers[i]);
|
||||
var amp = _ActiveSpectrum.GetAmplitude(_Wavelengths[i], _ComponentsPerOctave, windSpeed, water.Gravity, out _Powers[i]);
|
||||
_Amplitudes[i] = Random.value * amp;
|
||||
_Amplitudes2[i] = Random.value * amp * _ReverseWaveWeight;
|
||||
_Amplitudes2[i] = Random.value * amp * ReverseWaveWeight;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -490,8 +595,6 @@ namespace WaveHarmonic.Crest
|
||||
}
|
||||
}
|
||||
|
||||
private protected override void DestroySharedResources() { }
|
||||
|
||||
#if UNITY_EDITOR
|
||||
void OnGUI()
|
||||
{
|
||||
@@ -503,16 +606,44 @@ namespace WaveHarmonic.Crest
|
||||
#endif
|
||||
}
|
||||
|
||||
partial class ShapeGerstner
|
||||
{
|
||||
static int s_InstanceCount;
|
||||
|
||||
private protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
s_InstanceCount++;
|
||||
}
|
||||
|
||||
private protected override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
|
||||
if (s_SwellSpectrum != null)
|
||||
{
|
||||
Helpers.Destroy(s_SwellSpectrum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
partial class ShapeGerstner : ISerializationCallbackReceiver
|
||||
{
|
||||
[SerializeField, HideInInspector]
|
||||
#pragma warning disable 414
|
||||
int _Version = 1;
|
||||
int _Version = 2;
|
||||
#pragma warning restore 414
|
||||
|
||||
void ISerializationCallbackReceiver.OnAfterDeserialize()
|
||||
{
|
||||
_Version = MigrateV1(_Version);
|
||||
|
||||
if (_Version < 2)
|
||||
{
|
||||
_Swell = false;
|
||||
}
|
||||
|
||||
_Version = MigrateV2(_Version);
|
||||
}
|
||||
|
||||
void ISerializationCallbackReceiver.OnBeforeSerialize()
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace WaveHarmonic.Crest
|
||||
[@Heading("Waves")]
|
||||
|
||||
[Tooltip("The spectrum that defines the water surface shape.")]
|
||||
[@Embedded]
|
||||
[@Embedded(defaultPropertyName: nameof(_ActiveSpectrum))]
|
||||
[@GenerateAPI]
|
||||
[SerializeField]
|
||||
internal WaveSpectrum _Spectrum;
|
||||
@@ -35,17 +35,25 @@ namespace WaveHarmonic.Crest
|
||||
[SerializeField]
|
||||
float _RespectShallowWaterAttenuation = 1f;
|
||||
|
||||
[Tooltip("Whether to use the wind direction on this component rather than the global wind direction.\n\nGlobal wind direction comes from the Water Renderer component.")]
|
||||
[@GenerateAPI]
|
||||
[@InlineToggle, SerializeField]
|
||||
bool _OverrideGlobalWindDirection;
|
||||
|
||||
[@Label("Wind Direction")]
|
||||
[Tooltip("Primary wave direction heading (degrees).\n\nThis is the angle from x axis in degrees that the waves are oriented towards. If a spline is being used to place the waves, this angle is relative to the spline.")]
|
||||
[@Predicated(nameof(_Mode), inverted: false, nameof(LodInputMode.Paint))]
|
||||
[@Predicated(nameof(_OverrideGlobalWindDirection), hide: true)]
|
||||
[@ShowComputedProperty(nameof(WaveDirectionHeadingAngle))]
|
||||
[@Range(-180, 180)]
|
||||
[@GenerateAPI]
|
||||
[@GenerateAPI(Getter.Custom)]
|
||||
[SerializeField]
|
||||
private protected float _WaveDirectionHeadingAngle = 0f;
|
||||
|
||||
[Tooltip("Whether to use the wind speed on this component rather than the global wind speed.\n\nGlobal wind speed comes from the Water Renderer component.")]
|
||||
[@GenerateAPI]
|
||||
[SerializeField]
|
||||
bool _OverrideGlobalWindSpeed = false;
|
||||
[@InlineToggle, SerializeField]
|
||||
bool _OverrideGlobalWindSpeed;
|
||||
|
||||
[Tooltip("Wind speed in km/h. Controls wave conditions.")]
|
||||
[@ShowComputedProperty(nameof(WindSpeedKPH))]
|
||||
@@ -86,19 +94,21 @@ namespace WaveHarmonic.Crest
|
||||
public static readonly int s_AxisX = Shader.PropertyToID("_Crest_AxisX");
|
||||
}
|
||||
|
||||
static WaveSpectrum s_DefaultSpectrum;
|
||||
private protected static WaveSpectrum DefaultSpectrum
|
||||
private protected virtual WaveSpectrum DefaultSpectrum => WindSpectrum;
|
||||
|
||||
static WaveSpectrum s_WindSpectrum;
|
||||
private protected static WaveSpectrum WindSpectrum
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_DefaultSpectrum == null)
|
||||
if (s_WindSpectrum == null)
|
||||
{
|
||||
s_DefaultSpectrum = ScriptableObject.CreateInstance<WaveSpectrum>();
|
||||
s_DefaultSpectrum.name = "Default Waves (instance)";
|
||||
s_DefaultSpectrum.hideFlags = HideFlags.DontSave | HideFlags.NotEditable;
|
||||
s_WindSpectrum = ScriptableObject.CreateInstance<WaveSpectrum>();
|
||||
s_WindSpectrum.name = "Wind Waves (instance)";
|
||||
s_WindSpectrum.hideFlags = HideFlags.DontSave | HideFlags.NotEditable;
|
||||
}
|
||||
|
||||
return s_DefaultSpectrum;
|
||||
return s_WindSpectrum;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,7 +123,7 @@ namespace WaveHarmonic.Crest
|
||||
internal static int s_RenderPassOverride = -1;
|
||||
|
||||
private protected WaveSpectrum _ActiveSpectrum = null;
|
||||
private protected Vector2 PrimaryWaveDirection => new(Mathf.Cos(Mathf.PI * _WaveDirectionHeadingAngle / 180f), Mathf.Sin(Mathf.PI * _WaveDirectionHeadingAngle / 180f));
|
||||
private protected Vector2 PrimaryWaveDirection => new(Mathf.Cos(Mathf.PI * WaveDirectionHeadingAngle / 180f), Mathf.Sin(Mathf.PI * WaveDirectionHeadingAngle / 180f));
|
||||
|
||||
/// <summary>
|
||||
/// The wind speed in kilometers per hour (KPH).
|
||||
@@ -121,7 +131,7 @@ namespace WaveHarmonic.Crest
|
||||
/// <remarks>
|
||||
/// Wind speed can come from this component or the <see cref="WaterRenderer"/>.
|
||||
/// </remarks>
|
||||
public float WindSpeedKPH => _OverrideGlobalWindSpeed || WaterRenderer.Instance == null ? _WindSpeed : WaterRenderer.Instance.WindSpeedKPH;
|
||||
public float WindSpeedKPH => _OverrideGlobalWindSpeed || WaterRenderer.Instance == null ? _WindSpeed : WaterRenderer.Instance.WindSpeed;
|
||||
|
||||
/// <summary>
|
||||
/// The wind speed in meters per second (MPS).
|
||||
@@ -301,7 +311,7 @@ namespace WaveHarmonic.Crest
|
||||
// Wave generation done in Draw. Keeps track to limit to once per frame.
|
||||
private protected int _LastGenerateFrameCount = -1;
|
||||
|
||||
internal override bool Enabled => _FirstCascade > -1 && WaterRenderer.Instance.Gravity != 0f && Mode switch
|
||||
internal override bool Enabled => _FirstCascade > -1 && (WaterRenderer.Instance == null || WaterRenderer.Instance.Gravity != 0f) && Mode switch
|
||||
{
|
||||
LodInputMode.Global => enabled && s_TransferWavesComputeShader != null,
|
||||
_ => base.Enabled,
|
||||
@@ -324,7 +334,6 @@ namespace WaveHarmonic.Crest
|
||||
private protected float MaximumReportedVerticalDisplacement { get; set; }
|
||||
private protected float MaximumReportedWavesDisplacement { get; set; }
|
||||
|
||||
static int s_InstanceCount = 0;
|
||||
|
||||
private protected bool UpdateDataEachFrame
|
||||
{
|
||||
@@ -349,7 +358,6 @@ namespace WaveHarmonic.Crest
|
||||
}
|
||||
|
||||
private protected abstract void ReportMaxDisplacement(WaterRenderer water);
|
||||
private protected abstract void DestroySharedResources();
|
||||
|
||||
private protected override void OnUpdate(WaterRenderer water)
|
||||
{
|
||||
@@ -367,26 +375,6 @@ namespace WaveHarmonic.Crest
|
||||
wrapper.SetFloat(ShaderIDs.s_MaximumAttenuationDepth, water._AnimatedWavesLod.ShallowsMaximumDepth);
|
||||
}
|
||||
|
||||
private protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
s_InstanceCount++;
|
||||
}
|
||||
|
||||
private protected void OnDestroy()
|
||||
{
|
||||
// Since FFTCompute resources are shared we will clear after last ShapeFFT is destroyed.
|
||||
if (--s_InstanceCount <= 0)
|
||||
{
|
||||
DestroySharedResources();
|
||||
|
||||
if (s_DefaultSpectrum != null)
|
||||
{
|
||||
Helpers.Destroy(s_DefaultSpectrum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private protected override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -441,6 +429,11 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
float GetWaveDirectionHeadingAngle()
|
||||
{
|
||||
return _OverrideGlobalWindDirection || WaterRenderer.Instance == null ? _WaveDirectionHeadingAngle : WaterRenderer.Instance.WindDirection;
|
||||
}
|
||||
}
|
||||
|
||||
partial class ShapeWaves
|
||||
@@ -455,6 +448,28 @@ namespace WaveHarmonic.Crest
|
||||
}
|
||||
}
|
||||
|
||||
partial class ShapeWaves
|
||||
{
|
||||
static int s_InstanceCount = 0;
|
||||
|
||||
private protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
s_InstanceCount++;
|
||||
}
|
||||
|
||||
private protected virtual void OnDestroy()
|
||||
{
|
||||
if (--s_InstanceCount <= 0)
|
||||
{
|
||||
if (s_WindSpectrum != null)
|
||||
{
|
||||
Helpers.Destroy(s_WindSpectrum);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
partial class ShapeWaves
|
||||
{
|
||||
[HideInInspector, SerializeField]
|
||||
@@ -486,5 +501,34 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
private protected int MigrateV2(int version)
|
||||
{
|
||||
// Version 2
|
||||
// - Global wind direction
|
||||
if (version < 2)
|
||||
{
|
||||
_OverrideGlobalWindDirection = true;
|
||||
version = 2;
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
partial class ShapeWaves
|
||||
{
|
||||
private protected override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
if (_Mode != LodInputMode.Global)
|
||||
{
|
||||
_OverrideGlobalWindSpeed = true;
|
||||
_OverrideGlobalWindDirection = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
@@ -18,6 +18,11 @@ namespace WaveHarmonic.Crest
|
||||
[@DecoratedField, SerializeField]
|
||||
internal Texture _Texture;
|
||||
|
||||
[Tooltip("Multiplies the texture sample.\n\nThis is useful for normalized textures. The four components map to the four color/alpha components of the texture (if they exist).\n\nIf you just want to fade out the input, consider using weight instead.")]
|
||||
[@GenerateAPI]
|
||||
[@DecoratedField, SerializeField]
|
||||
Vector4 _Multiplier = Vector4.one;
|
||||
|
||||
private protected abstract ComputeShader TextureShader { get; }
|
||||
internal override bool IsEnabled => _Texture != null;
|
||||
internal override bool HasHeightRange => false;
|
||||
@@ -41,6 +46,7 @@ namespace WaveHarmonic.Crest
|
||||
wrapper.SetVector(ShaderIDs.s_TexturePosition, transform.position.XZ());
|
||||
wrapper.SetVector(ShaderIDs.s_TextureRotation, rotation);
|
||||
wrapper.SetVector(ShaderIDs.s_Resolution, new(_Texture.width, _Texture.height));
|
||||
wrapper.SetVector(ShaderIDs.s_Multiplier, _Multiplier);
|
||||
wrapper.SetFloat(ShaderIDs.s_FeatherWidth, _Input.FeatherWidth);
|
||||
wrapper.SetTexture(ShaderIDs.s_Texture, _Texture);
|
||||
wrapper.SetInteger(ShaderIDs.s_Blend, (int)_Input.Blend);
|
||||
|
||||
@@ -13,17 +13,14 @@ namespace WaveHarmonic.Crest
|
||||
/// <remarks>
|
||||
/// Each mode has its strengths and weaknesses.
|
||||
/// </remarks>
|
||||
[@GenerateDoc]
|
||||
public enum WatertightHullMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Uses <see cref="AnimatedWavesLod"/> to remove water.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.WatertightHullMode.Displacement"/>
|
||||
[Tooltip("Use displacement to remove water.\n\nUsing displacement will also affect the underwater and can nest bouyant objects. Requires the displacement layer to be enabled.")]
|
||||
Displacement,
|
||||
|
||||
/// <summary>
|
||||
/// Uses <see cref="ClipLod"/> to remove water.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.WatertightHullMode.Clip"/>
|
||||
[Tooltip("Clips the surface to remove water.\n\nThis option is more precise and can be submerged.")]
|
||||
Clip,
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
// We do not add height to displacement directly for better precision and layering.
|
||||
@@ -21,7 +21,6 @@ namespace WaveHarmonic.Crest
|
||||
internal override Color GizmoColor => s_GizmoColor;
|
||||
private protected override Color ClearColor => Color.black;
|
||||
private protected override bool NeedToReadWriteTextureData => true;
|
||||
internal override bool RunsInHeadless => true;
|
||||
|
||||
private protected override GraphicsFormat RequestedTextureFormat => _TextureFormatMode switch
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
@@ -18,32 +18,23 @@ namespace WaveHarmonic.Crest
|
||||
/// <summary>
|
||||
/// Texture format preset.
|
||||
/// </summary>
|
||||
[@GenerateDoc]
|
||||
public enum LodTextureFormatMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Uses <see cref="Lod.TextureFormat"/>.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.LodTextureFormatMode.Manual"/>
|
||||
[Tooltip("Uses the Texture Format property.")]
|
||||
Manual,
|
||||
|
||||
/// <summary>
|
||||
/// Chooses a texture format for performance.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.LodTextureFormatMode.Performance"/>
|
||||
[Tooltip("Chooses a texture format for performance.")]
|
||||
Performance = 100,
|
||||
|
||||
/// <summary>
|
||||
/// Chooses a texture format for precision.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This format can reduce artifacts.
|
||||
/// </remarks>
|
||||
/// <inheritdoc cref="Generated.LodTextureFormatMode.Precision"/>
|
||||
[Tooltip("Chooses a texture format for precision.\n\nThis format can reduce artifacts.")]
|
||||
Precision = 200,
|
||||
|
||||
/// <summary>
|
||||
/// Chooses a texture format based on another.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// For example, Dynamic Waves will match precision of Animated Waves.
|
||||
/// </remarks>
|
||||
/// <inheritdoc cref="Generated.LodTextureFormatMode.Automatic"/>
|
||||
[Tooltip("Chooses a texture format based on another.\n\nFor example, Dynamic Waves will match precision of Animated Waves.")]
|
||||
Automatic = 300,
|
||||
}
|
||||
|
||||
@@ -61,11 +52,13 @@ namespace WaveHarmonic.Crest
|
||||
[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)]
|
||||
[@GenerateAPI(Setter.Dirty)]
|
||||
[@DecoratedField, SerializeField]
|
||||
[@InlineToggle(fix: true), 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)]
|
||||
[@ShowComputedProperty(nameof(Resolution))]
|
||||
[@Delayed]
|
||||
[@GenerateAPI(Getter.Custom, Setter.Dirty)]
|
||||
[SerializeField]
|
||||
@@ -151,8 +144,6 @@ namespace WaveHarmonic.Crest
|
||||
// Always use linear filtering.
|
||||
GraphicsFormatUsage.Linear;
|
||||
|
||||
internal virtual bool RunsInHeadless => false;
|
||||
|
||||
private protected BufferedData<RenderTexture> _Targets;
|
||||
internal RenderTexture DataTexture => _Targets.Current;
|
||||
internal RenderTexture GetDataTexture(int frameDelta) => _Targets.Previous(frameDelta);
|
||||
@@ -218,8 +209,14 @@ namespace WaveHarmonic.Crest
|
||||
ReAllocate();
|
||||
}
|
||||
|
||||
_Targets.Flip();
|
||||
_SamplingParameters.Flip();
|
||||
#if UNITY_EDITOR
|
||||
// Fixes flickering in frame debugger when navigating draw calls.
|
||||
if (!UnityEditor.EditorApplication.isPaused || Time.deltaTime > 0)
|
||||
#endif
|
||||
{
|
||||
_Targets.Flip();
|
||||
_SamplingParameters.Flip();
|
||||
}
|
||||
|
||||
UpdateSamplingParameters();
|
||||
}
|
||||
@@ -245,12 +242,11 @@ namespace WaveHarmonic.Crest
|
||||
{
|
||||
FlipBuffers();
|
||||
|
||||
buffer.BeginSample(Name);
|
||||
buffer.BeginSample(ID);
|
||||
|
||||
if (_TargetsToClear > 0 || AlwaysClear)
|
||||
{
|
||||
buffer.SetRenderTarget(DataTexture, 0, CubemapFace.Unknown, -1);
|
||||
buffer.ClearRenderTarget(RTClearFlags.Color, ClearColor, 0, 0);
|
||||
CoreUtils.SetRenderTarget(buffer, DataTexture, ClearFlag.Color, ClearColor);
|
||||
|
||||
_TargetsToClear--;
|
||||
}
|
||||
@@ -270,7 +266,7 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
Queryable?.UpdateQueries(_Water);
|
||||
|
||||
buffer.EndSample(Name);
|
||||
buffer.EndSample(ID);
|
||||
}
|
||||
|
||||
private protected bool SubmitDraws(CommandBuffer buffer, Inputs draws, RenderTargetIdentifier target, int pass = -1, bool filter = false)
|
||||
@@ -323,8 +319,8 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
// Parameters override RTI values:
|
||||
// https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetRenderTarget.html
|
||||
buffer.SetRenderTarget(target, 0, CubemapFace.Unknown, slice);
|
||||
buffer.SetGlobalInt(ShaderIDs.s_LodIndex, slice);
|
||||
CoreUtils.SetRenderTarget(buffer, target, depthSlice: slice);
|
||||
buffer.SetGlobalInteger(ShaderIDs.s_LodIndex, slice);
|
||||
|
||||
// This will work for CG but not for HDRP hlsl files.
|
||||
buffer.SetViewProjectionMatrices(_ViewMatrices[slice], _Water.GetProjectionMatrix(slice));
|
||||
@@ -373,24 +369,35 @@ namespace WaveHarmonic.Crest
|
||||
wrapper.Dispatch(1, size, 1);
|
||||
}
|
||||
|
||||
void UpdateSamplingParameters()
|
||||
void UpdateSamplingParameters(bool initialize = false)
|
||||
{
|
||||
for (var slice = 0; slice < Slices; slice++)
|
||||
var position = _Water.Position;
|
||||
var resolution = _Enabled ? Resolution : TextureArrayHelpers.k_SmallTextureSize;
|
||||
|
||||
var parameters = _SamplingParameters.Current;
|
||||
var levels = Slices;
|
||||
|
||||
for (var slice = 0; slice < levels; slice++)
|
||||
{
|
||||
// Find snap period.
|
||||
var texel = 2f * 2f * _Water.CalcLodScale(slice) / Resolution;
|
||||
var texel = 2f * 2f * _Water._CascadeData.Current[slice].x / resolution;
|
||||
// Snap so that shape texels are stationary.
|
||||
var snapped = _Water.Root.position - new Vector3(Mathf.Repeat(_Water.Root.position.x, texel), 0, Mathf.Repeat(_Water.Root.position.z, texel));
|
||||
var snapped = position - new Vector3(Mathf.Repeat(position.x, texel), 0, Mathf.Repeat(position.z, texel));
|
||||
|
||||
var cascade = new Cascade(snapped.XZ(), texel, Resolution);
|
||||
var cascade = new Cascade(snapped.XZ(), texel, resolution);
|
||||
_Cascades[slice] = cascade;
|
||||
_SamplingParameters.Current[slice] = cascade.Packed;
|
||||
parameters[slice] = cascade.Packed;
|
||||
if (initialize && BufferCount > 1) _SamplingParameters.Previous(1)[slice] = cascade.Packed;
|
||||
|
||||
_ViewMatrices[slice] = WaterRenderer.CalculateViewMatrixFromSnappedPositionRHS(snapped);
|
||||
}
|
||||
|
||||
Shader.SetGlobalVector(_SamplingParametersShaderID, new(_Water.LodLevels, Resolution, 1f / Resolution, 0));
|
||||
Shader.SetGlobalVectorArray(_SamplingParametersCascadeShaderID, _SamplingParameters.Current);
|
||||
if (initialize)
|
||||
{
|
||||
Shader.SetGlobalVector(_SamplingParametersShaderID, new(levels, resolution, 1f / resolution, 0));
|
||||
}
|
||||
|
||||
Shader.SetGlobalVectorArray(_SamplingParametersCascadeShaderID, parameters);
|
||||
|
||||
if (BufferCount > 1)
|
||||
{
|
||||
@@ -490,13 +497,6 @@ namespace WaveHarmonic.Crest
|
||||
return;
|
||||
}
|
||||
|
||||
// Some simulations are pointless in non-interactive mode.
|
||||
if (_Water.IsRunningHeadless && !RunsInHeadless)
|
||||
{
|
||||
_Valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate textures.
|
||||
{
|
||||
// Find a compatible texture format.
|
||||
@@ -522,6 +522,21 @@ namespace WaveHarmonic.Crest
|
||||
if (_Water.IsRunningWithoutGraphics) return;
|
||||
// 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));
|
||||
|
||||
UpdateSamplingParameters(initialize: true);
|
||||
}
|
||||
|
||||
internal virtual void Enable()
|
||||
@@ -545,13 +560,16 @@ namespace WaveHarmonic.Crest
|
||||
});
|
||||
}
|
||||
|
||||
internal virtual void AfterExecute()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private protected virtual void Allocate()
|
||||
{
|
||||
_Targets = new(BufferCount, CreateLodDataTextures);
|
||||
_Targets.RunLambda(Clear);
|
||||
|
||||
_SamplingParameters = new(BufferCount, () => new Vector4[k_MaximumSlices]);
|
||||
|
||||
// Bind globally once here on init, which will bind to all graphics shaders (not compute)
|
||||
Shader.SetGlobalTexture(_TextureShaderID, DataTexture);
|
||||
|
||||
@@ -580,7 +598,7 @@ namespace WaveHarmonic.Crest
|
||||
SetGlobals(current);
|
||||
}
|
||||
|
||||
int GetResolution() => _OverrideResolution ? _Resolution : Water.LodResolution;
|
||||
int GetResolution() => _OverrideResolution || Water == null ? _Resolution : Water.LodResolution;
|
||||
|
||||
private protected void ReAllocate()
|
||||
{
|
||||
@@ -597,6 +615,8 @@ namespace WaveHarmonic.Crest
|
||||
});
|
||||
|
||||
_ReAllocateTexture = false;
|
||||
|
||||
UpdateSamplingParameters(initialize: true);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
@@ -641,6 +661,7 @@ namespace WaveHarmonic.Crest
|
||||
/// 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
|
||||
{
|
||||
/// <summary>
|
||||
@@ -662,5 +683,10 @@ namespace WaveHarmonic.Crest
|
||||
// None providers are not IQueryable.
|
||||
Queryable = Provider as IQueryable;
|
||||
}
|
||||
|
||||
internal override void AfterExecute()
|
||||
{
|
||||
Queryable?.SendReadBack(_Water);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
@@ -9,6 +9,7 @@ namespace WaveHarmonic.Crest
|
||||
/// <summary>
|
||||
/// A persistent simulation that moves around with a displacement LOD.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public abstract partial class PersistentLod : Lod
|
||||
{
|
||||
[Tooltip("Frequency to run the simulation, in updates per second.\n\nLower frequencies are more efficient but may lead to visible jitter or slowness.")]
|
||||
@@ -37,6 +38,8 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
internal int LastUpdateSubstepCount { get; private set; }
|
||||
|
||||
private protected virtual int Kernel => 0;
|
||||
private protected virtual bool SkipFlipBuffers => false;
|
||||
private protected abstract ComputeShader SimulationShader { get; }
|
||||
private protected abstract void GetSubstepData(float timeToSimulate, out int substeps, out float delta);
|
||||
|
||||
@@ -61,9 +64,12 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
internal override void BuildCommandBuffer(WaterRenderer water, CommandBuffer buffer)
|
||||
{
|
||||
buffer.BeginSample(Name);
|
||||
buffer.BeginSample(ID);
|
||||
|
||||
FlipBuffers();
|
||||
if (!SkipFlipBuffers)
|
||||
{
|
||||
FlipBuffers();
|
||||
}
|
||||
|
||||
var slices = water.LodLevels;
|
||||
|
||||
@@ -91,19 +97,19 @@ namespace WaveHarmonic.Crest
|
||||
// artifacts if not and there is a renderer input. Happens for foam and dynamic
|
||||
// waves. Confusing/concerning.
|
||||
buffer.GetTemporaryRT(ShaderIDs.s_TemporaryPersistentTarget, DataTexture.descriptor);
|
||||
buffer.SetRenderTarget(ShaderIDs.s_TemporaryPersistentTarget, 0, CubemapFace.Unknown, -1);
|
||||
buffer.ClearRenderTarget(RTClearFlags.Color, ClearColor, 0, 0);
|
||||
CoreUtils.SetRenderTarget(buffer, ShaderIDs.s_TemporaryPersistentTarget, ClearFlag.Color, ClearColor);
|
||||
}
|
||||
|
||||
var target = new RenderTargetIdentifier(DataTexture);
|
||||
var source = new RenderTargetIdentifier(ShaderIDs.s_TemporaryPersistentTarget);
|
||||
var current = target;
|
||||
|
||||
var wrapper = new PropertyWrapperCompute(buffer, SimulationShader, Kernel);
|
||||
|
||||
for (var substep = 0; substep < substeps; substep++)
|
||||
{
|
||||
var isFirstStep = substep == 0;
|
||||
var frame = isFirstStep ? 1 : 0;
|
||||
var wrapper = new PropertyWrapperCompute(buffer, SimulationShader, 0);
|
||||
|
||||
// Record how much we caught up
|
||||
_TimeToSimulate -= delta;
|
||||
@@ -168,14 +174,15 @@ namespace WaveHarmonic.Crest
|
||||
// Set the target texture as to make sure we catch the 'pong' each frame.
|
||||
Shader.SetGlobalTexture(_TextureShaderID, DataTexture);
|
||||
|
||||
buffer.EndSample(Name);
|
||||
buffer.EndSample(ID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set any simulation specific shader parameters.
|
||||
/// </summary>
|
||||
private protected virtual void SetAdditionalSimulationParameters<T>(T properties) where T : IPropertyWrapper
|
||||
private protected virtual void SetAdditionalSimulationParameters(PropertyWrapperCompute properties)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
using WaveHarmonic.Crest.Internal;
|
||||
using WaveHarmonic.Crest.Utility;
|
||||
|
||||
namespace WaveHarmonic.Crest
|
||||
{
|
||||
@@ -84,60 +85,46 @@ namespace WaveHarmonic.Crest
|
||||
}
|
||||
}
|
||||
|
||||
if (_UseDisplacements)
|
||||
var success = _UseDisplacements
|
||||
? collProvider.RetrieveSucceeded(collProvider.Query(GetHashCode(), _ObjectWidth, _SamplePositions, _ResultDisplacements, _UseNormals ? _ResultNormals : null, null, _Layer))
|
||||
: collProvider.RetrieveSucceeded(collProvider.Query(GetHashCode(), _ObjectWidth, _SamplePositions, _ResultHeights, _UseNormals ? _ResultNormals : null, null, _Layer));
|
||||
|
||||
#if !UNITY_EDITOR
|
||||
// Gizmos handle this in editor.
|
||||
if (success)
|
||||
{
|
||||
if (collProvider.RetrieveSucceeded(collProvider.Query(GetHashCode(), _ObjectWidth, _SamplePositions, _ResultDisplacements, _UseNormals ? _ResultNormals : null, null, _Layer)))
|
||||
{
|
||||
for (var i = 0; i < _Steps; i++)
|
||||
{
|
||||
for (var j = 0; j < _Steps; j++)
|
||||
{
|
||||
var result = _SamplePositions[j * _Steps + i];
|
||||
result.y = water.SeaLevel;
|
||||
result += _ResultDisplacements[j * _Steps + i];
|
||||
|
||||
var norm = _UseNormals ? _ResultNormals[j * _Steps + i] : Vector3.up;
|
||||
|
||||
DebugDrawCross(result, norm, Mathf.Min(_StepSize / 4f, 1f), Color.green);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (collProvider.RetrieveSucceeded(collProvider.Query(GetHashCode(), _ObjectWidth, _SamplePositions, _ResultHeights, _UseNormals ? _ResultNormals : null, null, _Layer)))
|
||||
{
|
||||
for (var i = 0; i < _Steps; i++)
|
||||
{
|
||||
for (var j = 0; j < _Steps; j++)
|
||||
{
|
||||
var result = _SamplePositions[j * _Steps + i];
|
||||
result.y = _ResultHeights[j * _Steps + i];
|
||||
|
||||
var norm = _UseNormals ? _ResultNormals[j * _Steps + i] : Vector3.up;
|
||||
|
||||
DebugDrawCross(result, norm, Mathf.Min(_StepSize / 4f, 1f), Color.green);
|
||||
}
|
||||
}
|
||||
}
|
||||
Render(water, Debug.DrawLine);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void DebugDrawCross(Vector3 pos, float r, Color col, float duration = 0f)
|
||||
internal void Render(WaterRenderer water, DebugUtility.DrawLine draw)
|
||||
{
|
||||
Debug.DrawLine(pos - Vector3.up * r, pos + Vector3.up * r, col, duration);
|
||||
Debug.DrawLine(pos - Vector3.right * r, pos + Vector3.right * r, col, duration);
|
||||
Debug.DrawLine(pos - Vector3.forward * r, pos + Vector3.forward * r, col, duration);
|
||||
}
|
||||
if (_SamplePositions == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public static void DebugDrawCross(Vector3 pos, Vector3 up, float r, Color col, float duration = 0f)
|
||||
{
|
||||
up.Normalize();
|
||||
var right = Vector3.Normalize(Vector3.Cross(up, Vector3.forward));
|
||||
var forward = Vector3.Cross(up, right);
|
||||
Debug.DrawLine(pos - up * r, pos + up * r, col, duration);
|
||||
Debug.DrawLine(pos - right * r, pos + right * r, col, duration);
|
||||
Debug.DrawLine(pos - forward * r, pos + forward * r, col, duration);
|
||||
for (var i = 0; i < _Steps; i++)
|
||||
{
|
||||
for (var j = 0; j < _Steps; j++)
|
||||
{
|
||||
var result = _SamplePositions[j * _Steps + i];
|
||||
|
||||
if (_UseDisplacements)
|
||||
{
|
||||
result.y = water.SeaLevel;
|
||||
result += _ResultDisplacements[j * _Steps + i];
|
||||
}
|
||||
else
|
||||
{
|
||||
result.y = _ResultHeights[j * _Steps + i];
|
||||
}
|
||||
|
||||
var normal = _UseNormals ? _ResultNormals[j * _Steps + i] : Vector3.up;
|
||||
DebugUtility.DrawCross(draw, result, normal, Mathf.Min(_StepSize / 4f, 1f), Color.green);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
// NOTE: DWP2 depends on this file. Any API changes need to be communicated to the DWP2 authors in advance.
|
||||
@@ -13,23 +13,18 @@ namespace WaveHarmonic.Crest
|
||||
/// <summary>
|
||||
/// A layer/event where queries are executed.
|
||||
/// </summary>
|
||||
[@GenerateDoc]
|
||||
public enum CollisionLayer
|
||||
{
|
||||
/// <summary>
|
||||
/// Include all displacement.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.CollisionLayer.Everything"/>
|
||||
[Tooltip("Include all displacement.")]
|
||||
Everything,
|
||||
|
||||
/// <summary>
|
||||
/// Only include Animated Waves.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.CollisionLayer.AfterAnimatedWaves"/>
|
||||
[Tooltip("Only include Animated Waves.")]
|
||||
AfterAnimatedWaves,
|
||||
|
||||
/// <summary>
|
||||
/// Include Animated Waves and Dynamic Waves.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.CollisionLayer.AfterDynamicWaves"/>
|
||||
[Tooltip("Include Animated Waves and Dynamic Waves.")]
|
||||
AfterDynamicWaves,
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
@@ -82,27 +82,28 @@ namespace WaveHarmonic.Crest
|
||||
{
|
||||
var layers = _Water.AnimatedWavesLod._CollisionLayers;
|
||||
|
||||
// Displacement is the fallback if there are no layers (ie single layer).
|
||||
if (layers == CollisionLayers.Nothing)
|
||||
{
|
||||
return _Displacement;
|
||||
}
|
||||
|
||||
if (layer == CollisionLayer.Everything)
|
||||
var everything = layer == CollisionLayer.Everything;
|
||||
|
||||
// Displacement is the final layer, if present.
|
||||
if (everything && layers.HasFlag(CollisionLayers.Displacement))
|
||||
{
|
||||
if (layers.HasFlag(CollisionLayers.Displacement))
|
||||
{
|
||||
return _Displacement;
|
||||
}
|
||||
return _Displacement;
|
||||
}
|
||||
|
||||
if (layer >= CollisionLayer.AfterDynamicWaves)
|
||||
// Chosen/fallback to Dynamic Waves.
|
||||
if ((everything || layer >= CollisionLayer.AfterDynamicWaves) &&
|
||||
layers.HasFlag(CollisionLayers.DynamicWaves) && _Water.DynamicWavesLod.Enabled)
|
||||
{
|
||||
if (layers.HasFlag(CollisionLayers.DynamicWaves) && _Water.DynamicWavesLod.Enabled)
|
||||
{
|
||||
return _DynamicWaves;
|
||||
}
|
||||
return _DynamicWaves;
|
||||
}
|
||||
|
||||
// If not single layer, this is always present.
|
||||
return _AnimatedWaves;
|
||||
}
|
||||
|
||||
@@ -131,6 +132,19 @@ namespace WaveHarmonic.Crest
|
||||
_Displacement.UpdateQueries(water);
|
||||
}
|
||||
|
||||
public void SendReadBack(WaterRenderer water, CollisionLayers layers)
|
||||
{
|
||||
// Will only submit readback if there are queries.
|
||||
_AnimatedWaves.SendReadBack(water);
|
||||
_DynamicWaves.SendReadBack(water);
|
||||
_Displacement.SendReadBack(water);
|
||||
}
|
||||
|
||||
public void SendReadBack(WaterRenderer water)
|
||||
{
|
||||
_Displacement.SendReadBack(water);
|
||||
}
|
||||
|
||||
public void CleanUp()
|
||||
{
|
||||
_AnimatedWaves.CleanUp();
|
||||
@@ -143,6 +157,7 @@ namespace WaveHarmonic.Crest
|
||||
{
|
||||
public static void UpdateQueries(this ICollisionProvider self, WaterRenderer water, CollisionLayer layer) => (self as CollisionQueryWithPasses)?.UpdateQueries(water, layer);
|
||||
public static void UpdateQueries(this ICollisionProvider self, WaterRenderer water) => (self as IQueryable)?.UpdateQueries(water);
|
||||
public static void SendReadBack(this ICollisionProvider self, WaterRenderer water, CollisionLayers layer) => (self as CollisionQueryWithPasses)?.SendReadBack(water, layer);
|
||||
public static void CleanUp(this ICollisionProvider self) => (self as IQueryable)?.CleanUp();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
using WaveHarmonic.Crest.Internal;
|
||||
using WaveHarmonic.Crest.Utility;
|
||||
|
||||
namespace WaveHarmonic.Crest
|
||||
{
|
||||
@@ -33,7 +34,7 @@ namespace WaveHarmonic.Crest
|
||||
{
|
||||
var endPos = transform.position + transform.forward * dist;
|
||||
Debug.DrawLine(transform.position, endPos, Color.green);
|
||||
CollisionAreaVisualizer.DebugDrawCross(endPos, 2f, Color.green, 0f);
|
||||
DebugUtility.DrawCross(Debug.DrawLine, endPos, 2f, Color.green, 0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
namespace WaveHarmonic.Crest
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
// Potential improvements
|
||||
@@ -43,6 +43,7 @@ namespace WaveHarmonic.Crest
|
||||
int RequestCount { get; }
|
||||
int QueryCount { get; }
|
||||
void UpdateQueries(WaterRenderer water);
|
||||
void SendReadBack(WaterRenderer water);
|
||||
void CleanUp();
|
||||
}
|
||||
|
||||
@@ -512,7 +513,20 @@ namespace WaveHarmonic.Crest
|
||||
if (_SegmentRegistrarRingBuffer.Current._QueryCount > 0)
|
||||
{
|
||||
ExecuteQueries();
|
||||
}
|
||||
}
|
||||
|
||||
public void SendReadBack(WaterRenderer water)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
// Seems to be a terrible memory leak coming from creating async GPU readbacks.
|
||||
// This was marked as resolved by Unity and confirmed fixed by forum posts.
|
||||
// May be worth keeping. See issue #630 for more details.
|
||||
if (!water._HeightQueries && !Application.isPlaying) return;
|
||||
#endif
|
||||
|
||||
if (_SegmentRegistrarRingBuffer.Current._QueryCount > 0)
|
||||
{
|
||||
// Remove oldest requests if we have hit the limit
|
||||
while (_Requests.Count >= k_MaximumRequests)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
@@ -10,19 +10,15 @@ namespace WaveHarmonic.Crest
|
||||
/// <summary>
|
||||
/// What transform to use for queries.
|
||||
/// </summary>
|
||||
[@GenerateDoc]
|
||||
public enum QuerySource
|
||||
{
|
||||
/// <summary>
|
||||
/// This game object's transform.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Generated.QuerySource.Transform"/>
|
||||
[Tooltip("This game object's transform.")]
|
||||
Transform,
|
||||
|
||||
/// <summary>
|
||||
/// The viewer's transform.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The viewer is the main camera the system uses.
|
||||
/// </remarks>
|
||||
/// <inheritdoc cref="Generated.QuerySource.Viewer"/>
|
||||
[Tooltip("The viewer's transform.\n\nThe viewer is the main camera the system uses.")]
|
||||
Viewer
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
@@ -226,7 +226,7 @@ namespace WaveHarmonic.Crest
|
||||
public bool Sample(Vector3 position, out Vector2 flow, float minimumLength = 0f)
|
||||
{
|
||||
var water = WaterRenderer.Instance;
|
||||
var flowProvider = WaterRenderer.Instance == null ? null : water.FlowLod.Provider;
|
||||
var flowProvider = water == null ? null : water.FlowLod.Provider;
|
||||
|
||||
if (flowProvider == null)
|
||||
{
|
||||
@@ -262,7 +262,7 @@ namespace WaveHarmonic.Crest
|
||||
bool Sample(Vector3 position, out Vector2 result)
|
||||
{
|
||||
var water = WaterRenderer.Instance;
|
||||
var depthProvider = WaterRenderer.Instance == null ? null : water.DepthLod.Provider;
|
||||
var depthProvider = water == null ? null : water.DepthLod.Provider;
|
||||
|
||||
if (depthProvider == null)
|
||||
{
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
#if d_UnityHDRP
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering.HighDefinition;
|
||||
|
||||
namespace WaveHarmonic.Crest
|
||||
@@ -14,36 +12,20 @@ namespace WaveHarmonic.Crest
|
||||
static SampleShadowsHDRP s_Instance;
|
||||
static readonly string s_Name = "Sample Shadows";
|
||||
|
||||
// These values come from unity_MatrxVP value in the frame debugger. unity_MatrxVP is marked as legacy and
|
||||
// breaks XR SPI. It is defined in:
|
||||
// "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/EditorShaderVariables.hlsl"
|
||||
static readonly Matrix4x4 s_Matrix = new
|
||||
(
|
||||
new(2f, 0f, 0f, 0f),
|
||||
new(0f, -2f, 0f, 0f),
|
||||
new(0f, 0f, 0.00990099f, 0f),
|
||||
new(-1f, 1f, 0.990099f, 1f)
|
||||
);
|
||||
|
||||
static class ShaderIDs
|
||||
{
|
||||
public static readonly int s_ViewProjectionMatrix = Shader.PropertyToID("_Crest_ViewProjectionMatrix");
|
||||
}
|
||||
|
||||
GameObject _GameObject;
|
||||
WaterRenderer _Water;
|
||||
int _XrTargetEyeIndex = -1;
|
||||
|
||||
protected override void Execute(CustomPassContext context)
|
||||
{
|
||||
var water = WaterRenderer.Instance;
|
||||
var water = _Water;
|
||||
|
||||
if (water == null || !water._ShadowLod.Enabled)
|
||||
if (!water._ShadowLod.Enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (!WaterRenderer.IsWithinEditorUpdate || EditorApplication.isPaused)
|
||||
if (!WaterRenderer.IsWithinEditorUpdate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -58,36 +40,19 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
camera.TryGetComponent<HDAdditionalCameraData>(out var cameraData);
|
||||
|
||||
if (cameraData != null && cameraData.xrRendering)
|
||||
// Skip the right eye for multi-pass as data is not stereo.
|
||||
if (Rendering.HDRP.SkipPassXR(ref _XrTargetEyeIndex, cameraData))
|
||||
{
|
||||
XRHelpers.UpdatePassIndex(ref _XrTargetEyeIndex);
|
||||
|
||||
// Skip the right eye as data is not stereo.
|
||||
if (_XrTargetEyeIndex == 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable for XR SPI otherwise input will not have correct world position.
|
||||
if (cameraData != null && cameraData.xrRendering && XRHelpers.IsSinglePass)
|
||||
{
|
||||
context.cmd.DisableShaderKeyword("STEREO_INSTANCING_ON");
|
||||
}
|
||||
Rendering.HDRP.DisableXR(context.cmd, cameraData);
|
||||
|
||||
// We cannot seem to override this matrix so a reference manually.
|
||||
context.cmd.SetGlobalMatrix(ShaderIDs.s_ViewProjectionMatrix, s_Matrix);
|
||||
water._ShadowLod.BuildCommandBuffer(water, context.cmd);
|
||||
|
||||
// Restore matrices otherwise remaining render will have incorrect matrices. Each pass is responsible for
|
||||
// restoring matrices if required.
|
||||
context.cmd.SetViewProjectionMatrices(camera.worldToCameraMatrix, camera.projectionMatrix);
|
||||
|
||||
// Restore XR SPI as we cannot rely on remaining pipeline to do it for us.
|
||||
if (cameraData != null && cameraData.xrRendering && XRHelpers.IsSinglePass)
|
||||
{
|
||||
context.cmd.EnableShaderKeyword("STEREO_INSTANCING_ON");
|
||||
}
|
||||
Rendering.HDRP.EnableXR(context.cmd, cameraData);
|
||||
}
|
||||
|
||||
internal static void Enable(WaterRenderer water)
|
||||
@@ -103,11 +68,12 @@ namespace WaveHarmonic.Crest
|
||||
(
|
||||
gameObject,
|
||||
ref s_Instance,
|
||||
s_Name,
|
||||
CustomPassInjectionPoint.BeforeTransparent
|
||||
WaterRenderer.k_DrawLodData,
|
||||
// Earliest point after shadow maps have populated.
|
||||
CustomPassInjectionPoint.AfterOpaqueAndSky
|
||||
);
|
||||
|
||||
s_Instance._GameObject = gameObject;
|
||||
s_Instance._Water = water;
|
||||
}
|
||||
|
||||
internal static void Disable()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
#if d_UnityURP
|
||||
@@ -32,7 +32,7 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
public override void RecordRenderGraph(RenderGraph graph, ContextContainer frame)
|
||||
{
|
||||
using (var builder = graph.AddUnsafePass<PassData>(k_Name, out var data))
|
||||
using (var builder = graph.AddUnsafePass<PassData>(WaterRenderer.k_DrawLodData, out var data))
|
||||
{
|
||||
data.Init(frame, builder);
|
||||
builder.AllowPassCulling(false);
|
||||
@@ -49,7 +49,7 @@ namespace WaveHarmonic.Crest
|
||||
public override void Execute(ScriptableRenderContext context, ref RenderingData data)
|
||||
{
|
||||
_PassData.Init(data.GetFrameData());
|
||||
var buffer = CommandBufferPool.Get(k_Name);
|
||||
var buffer = CommandBufferPool.Get(WaterRenderer.k_DrawLodData);
|
||||
Execute(context, buffer, _PassData);
|
||||
context.ExecuteCommandBuffer(buffer);
|
||||
CommandBufferPool.Release(buffer);
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
#if d_UnityURP
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
@@ -12,55 +11,38 @@ namespace WaveHarmonic.Crest
|
||||
{
|
||||
sealed partial class SampleShadowsURP : ScriptableRenderPass
|
||||
{
|
||||
const string k_Name = "Crest Shadow Data";
|
||||
|
||||
static SampleShadowsURP s_Instance;
|
||||
internal static bool Created => s_Instance != null;
|
||||
|
||||
WaterRenderer _Water;
|
||||
|
||||
SampleShadowsURP(RenderPassEvent renderPassEvent)
|
||||
{
|
||||
this.renderPassEvent = renderPassEvent;
|
||||
}
|
||||
|
||||
internal static void Enable()
|
||||
internal static void Enable(WaterRenderer water)
|
||||
{
|
||||
s_Instance ??= new(RenderPassEvent.AfterRenderingSkybox);
|
||||
|
||||
RenderPipelineManager.beginCameraRendering -= EnqueuePass;
|
||||
RenderPipelineManager.beginCameraRendering += EnqueuePass;
|
||||
|
||||
RenderPipelineManager.activeRenderPipelineTypeChanged -= s_Instance.OnActiveRenderPipelineTypeChanged;
|
||||
RenderPipelineManager.activeRenderPipelineTypeChanged += s_Instance.OnActiveRenderPipelineTypeChanged;
|
||||
s_Instance ??= new(RenderPassEvent.AfterRenderingShadows);
|
||||
s_Instance._Water = water;
|
||||
}
|
||||
|
||||
internal static void Disable()
|
||||
internal static void EnqueuePass(ScriptableRenderContext context, Camera camera)
|
||||
{
|
||||
// TODO: Currently on RP change this method can be called with Enable ever being called leading to null
|
||||
// exceptions. It can be removed once those problems are sorted.
|
||||
if (s_Instance != null)
|
||||
if (s_Instance == null)
|
||||
{
|
||||
RenderPipelineManager.activeRenderPipelineTypeChanged -= s_Instance.OnActiveRenderPipelineTypeChanged;
|
||||
return;
|
||||
}
|
||||
|
||||
RenderPipelineManager.beginCameraRendering -= EnqueuePass;
|
||||
}
|
||||
var water = s_Instance._Water;
|
||||
|
||||
void OnActiveRenderPipelineTypeChanged()
|
||||
{
|
||||
Disable();
|
||||
}
|
||||
|
||||
static void EnqueuePass(ScriptableRenderContext context, Camera camera)
|
||||
{
|
||||
var water = WaterRenderer.Instance;
|
||||
|
||||
if (water == null || !water._ShadowLod.Enabled)
|
||||
if (!water._ShadowLod.Enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (!WaterRenderer.IsWithinEditorUpdate || EditorApplication.isPaused)
|
||||
if (!WaterRenderer.IsWithinEditorUpdate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -84,7 +66,7 @@ namespace WaveHarmonic.Crest
|
||||
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
|
||||
#endif
|
||||
{
|
||||
var water = WaterRenderer.Instance;
|
||||
var water = _Water;
|
||||
|
||||
if (water == null || !water._ShadowLod.Enabled)
|
||||
{
|
||||
@@ -103,30 +85,16 @@ namespace WaveHarmonic.Crest
|
||||
var camera = renderingData.cameraData.camera;
|
||||
|
||||
#if !UNITY_6000_0_OR_NEWER
|
||||
var buffer = CommandBufferPool.Get(k_Name);
|
||||
var buffer = CommandBufferPool.Get(WaterRenderer.k_DrawLodData);
|
||||
#endif
|
||||
|
||||
// We need to check the mask or it will cause entire pipeline to output black. Appears to only affect URP.
|
||||
var isStereoRendering = renderingData.cameraData.xrRendering && XRHelpers.IsSinglePass &&
|
||||
camera.stereoTargetEye == StereoTargetEyeMask.Both;
|
||||
|
||||
// Disable for XR SPI otherwise input will not have correct world position.
|
||||
if (isStereoRendering)
|
||||
{
|
||||
buffer.DisableShaderKeyword("STEREO_INSTANCING_ON");
|
||||
}
|
||||
Rendering.URP.DisableXR(buffer, renderingData.cameraData);
|
||||
|
||||
water._ShadowLod.BuildCommandBuffer(water, buffer);
|
||||
|
||||
// Restore matrices otherwise remaining render will have incorrect matrices. Each pass is responsible for
|
||||
// restoring matrices if required.
|
||||
buffer.SetViewProjectionMatrices(camera.worldToCameraMatrix, camera.projectionMatrix);
|
||||
|
||||
// Restore XR SPI as we cannot rely on remaining pipeline to do it for us.
|
||||
if (isStereoRendering)
|
||||
{
|
||||
buffer.EnableShaderKeyword("STEREO_INSTANCING_ON");
|
||||
}
|
||||
Rendering.URP.EnableXR(buffer, renderingData.cameraData);
|
||||
|
||||
#if !UNITY_6000_0_OR_NEWER
|
||||
context.ExecuteCommandBuffer(buffer);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
@@ -32,10 +32,11 @@ namespace WaveHarmonic.Crest
|
||||
get
|
||||
{
|
||||
var color = Color.clear;
|
||||
var surface = _Water.Surface;
|
||||
|
||||
if (_Water.Material != null)
|
||||
if (surface.Material != null && surface.Material.HasColor(WaterRenderer.ShaderIDs.s_Scattering))
|
||||
{
|
||||
color = _Water.Material.GetColor(WaterRenderer.ShaderIDs.s_Scattering).MaybeLinear();
|
||||
color = surface.Material.GetColor(WaterRenderer.ShaderIDs.s_Scattering).MaybeLinear();
|
||||
color.a = 0f;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace WaveHarmonic.Crest
|
||||
{
|
||||
partial class ShadowLod
|
||||
{
|
||||
internal void OnBeginCameraRendering(ScriptableRenderContext context, Camera camera)
|
||||
{
|
||||
// TODO: refactor this similar to MaskRenderer.
|
||||
if (!RenderPipelineHelper.IsLegacy)
|
||||
{
|
||||
#if d_UnityURP
|
||||
if (RenderPipelineHelper.IsUniversal)
|
||||
{
|
||||
SampleShadowsURP.EnqueuePass(context, camera);
|
||||
}
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// Do not execute when editor is not active to conserve power and prevent possible leaks.
|
||||
if (!UnityEditorInternal.InternalEditorUtility.isApplicationActive)
|
||||
{
|
||||
CopyShadowMapBuffer?.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!WaterRenderer.IsWithinEditorUpdate)
|
||||
{
|
||||
CopyShadowMapBuffer?.Clear();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
var water = _Water;
|
||||
|
||||
if (water == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!WaterRenderer.ShouldRender(camera, water.Surface.Layer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (camera == water.Viewer && CopyShadowMapBuffer != null)
|
||||
{
|
||||
if (_Light != null)
|
||||
{
|
||||
// Calling this in OnPreRender was too late to be executed in the same frame.
|
||||
_Light.RemoveCommandBuffer(LightEvent.BeforeScreenspaceMask, CopyShadowMapBuffer);
|
||||
_Light.AddCommandBuffer(LightEvent.BeforeScreenspaceMask, CopyShadowMapBuffer);
|
||||
}
|
||||
|
||||
// Disable for XR SPI otherwise input will not have correct world position.
|
||||
Rendering.BIRP.DisableXR(CopyShadowMapBuffer, camera);
|
||||
|
||||
BuildCommandBuffer(water, CopyShadowMapBuffer);
|
||||
|
||||
// Restore XR SPI as we cannot rely on remaining pipeline to do it for us.
|
||||
Rendering.BIRP.EnableXR(CopyShadowMapBuffer, camera);
|
||||
}
|
||||
}
|
||||
|
||||
internal void OnEndCameraRendering(Camera camera)
|
||||
{
|
||||
if (!RenderPipelineHelper.IsLegacy)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// Do not execute when editor is not active to conserve power and prevent possible leaks.
|
||||
if (!UnityEditorInternal.InternalEditorUtility.isApplicationActive)
|
||||
{
|
||||
CopyShadowMapBuffer?.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!WaterRenderer.IsWithinEditorUpdate)
|
||||
{
|
||||
CopyShadowMapBuffer?.Clear();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
var water = _Water;
|
||||
|
||||
if (water == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!WaterRenderer.ShouldRender(camera, water.Surface.Layer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (camera == water.Viewer)
|
||||
{
|
||||
// CBs added to a light are executed for every camera, but the LOD data is only
|
||||
// supports a single camera. Removing the CB after the camera renders restricts the
|
||||
// CB to one camera. Careful of recursive rendering for planar reflections, as it
|
||||
// executes a camera within this camera's frame.
|
||||
if (_Light != null && CopyShadowMapBuffer != null)
|
||||
{
|
||||
_Light.RemoveCommandBuffer(LightEvent.BeforeScreenspaceMask, CopyShadowMapBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7a4edb90370784ae2be24a7f430ee23e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,4 +1,4 @@
|
||||
// Crest Water System
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
// BIRP fallback not really tested yet - shaders need fixing up.
|
||||
@@ -20,7 +20,7 @@ namespace WaveHarmonic.Crest
|
||||
/// sampling for (very) soft shadows. Soft shadows is red, hard shadows is green.
|
||||
/// </remarks>
|
||||
[FilterEnum(nameof(_TextureFormatMode), Filtered.Mode.Exclude, (int)LodTextureFormatMode.Automatic)]
|
||||
public sealed partial class ShadowLod : Lod
|
||||
public sealed partial class ShadowLod : PersistentLod
|
||||
{
|
||||
[@Space(10)]
|
||||
|
||||
@@ -77,13 +77,14 @@ namespace WaveHarmonic.Crest
|
||||
public static readonly int s_Scale = Shader.PropertyToID("_Crest_Scale");
|
||||
public static readonly int s_JitterDiameters_CurrentFrameWeights = Shader.PropertyToID("_Crest_JitterDiameters_CurrentFrameWeights");
|
||||
public static readonly int s_MainCameraProjectionMatrix = Shader.PropertyToID("_Crest_MainCameraProjectionMatrix");
|
||||
public static readonly int s_SimDeltaTime = Shader.PropertyToID("_Crest_SimDeltaTime");
|
||||
|
||||
// BIRP only.
|
||||
public static readonly int s_ShadowCastersPresent = Shader.PropertyToID("_Crest_ShadowCastersPresent");
|
||||
public static readonly int s_ShadowPassExecuteLastFrame = Shader.PropertyToID("_Crest_ShadowPassExecuteLastFrame");
|
||||
public static readonly int s_ClearShadows = Shader.PropertyToID("_Crest_ClearShadows");
|
||||
}
|
||||
|
||||
const string k_DrawLodSample = "Sample";
|
||||
|
||||
const float k_MaximumJitter = 32f;
|
||||
|
||||
internal static readonly Color s_GizmoColor = new(0f, 0f, 0f, 0.5f);
|
||||
@@ -120,6 +121,13 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
Error _Error;
|
||||
|
||||
private protected override int Kernel => (int)RenderPipelineHelper.RenderPipeline;
|
||||
private protected override bool SkipFlipBuffers => true;
|
||||
private protected override ComputeShader SimulationShader => WaterResources.Instance.Compute._UpdateShadow;
|
||||
|
||||
bool _IsSimulationBuffer;
|
||||
|
||||
|
||||
internal override void Initialize()
|
||||
{
|
||||
if (WaterResources.Instance.Shaders._UpdateShadow == null)
|
||||
@@ -178,7 +186,7 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
if (RenderPipelineHelper.IsLegacy)
|
||||
{
|
||||
Helpers.SetGlobalBoolean(ShaderIDs.s_ShadowCastersPresent, true);
|
||||
Helpers.SetGlobalBoolean(ShaderIDs.s_ShadowPassExecuteLastFrame, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,14 +194,6 @@ namespace WaveHarmonic.Crest
|
||||
{
|
||||
base.Enable();
|
||||
|
||||
if (RenderPipelineHelper.IsLegacy)
|
||||
{
|
||||
Camera.onPreCull -= OnPreCullCamera;
|
||||
Camera.onPreCull += OnPreCullCamera;
|
||||
Camera.onPostRender -= OnPostRenderCamera;
|
||||
Camera.onPostRender += OnPostRenderCamera;
|
||||
}
|
||||
|
||||
CleanUpShadowCommandBuffers();
|
||||
|
||||
if (RenderPipelineHelper.IsHighDefinition)
|
||||
@@ -205,7 +205,7 @@ namespace WaveHarmonic.Crest
|
||||
else if (RenderPipelineHelper.IsUniversal)
|
||||
{
|
||||
#if d_UnityURP
|
||||
SampleShadowsURP.Enable();
|
||||
SampleShadowsURP.Enable(_Water);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -217,16 +217,9 @@ namespace WaveHarmonic.Crest
|
||||
CleanUpShadowCommandBuffers();
|
||||
Shader.SetGlobalFloat(ShaderIDs.s_DynamicSoftShadowsFactor, 1f);
|
||||
|
||||
Camera.onPreCull -= OnPreCullCamera;
|
||||
Camera.onPostRender -= OnPostRenderCamera;
|
||||
|
||||
#if d_UnityHDRP
|
||||
SampleShadowsHDRP.Disable();
|
||||
#endif
|
||||
|
||||
#if d_UnityURP
|
||||
SampleShadowsURP.Disable();
|
||||
#endif
|
||||
}
|
||||
|
||||
internal override void Destroy()
|
||||
@@ -265,7 +258,7 @@ namespace WaveHarmonic.Crest
|
||||
else if (RenderPipelineHelper.IsUniversal)
|
||||
{
|
||||
#if d_UnityURP
|
||||
SampleShadowsURP.Enable();
|
||||
SampleShadowsURP.Enable(_Water);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -276,106 +269,6 @@ namespace WaveHarmonic.Crest
|
||||
_Targets.RunLambda(buffer => Clear(buffer));
|
||||
}
|
||||
|
||||
void OnPreCullCamera(Camera camera)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
// Do not execute when editor is not active to conserve power and prevent possible leaks.
|
||||
if (!UnityEditorInternal.InternalEditorUtility.isApplicationActive)
|
||||
{
|
||||
CopyShadowMapBuffer?.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!WaterRenderer.IsWithinEditorUpdate)
|
||||
{
|
||||
CopyShadowMapBuffer?.Clear();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
var water = _Water;
|
||||
|
||||
if (water == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Helpers.MaskIncludesLayer(camera.cullingMask, water.Layer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (camera == water.Viewer && CopyShadowMapBuffer != null)
|
||||
{
|
||||
// Calling this in OnPreRender was too late to be executed in the same frame.
|
||||
AddCommandBufferToPrimaryLight();
|
||||
|
||||
// Disable for XR SPI otherwise input will not have correct world position.
|
||||
if (camera.stereoEnabled && XRHelpers.IsSinglePass)
|
||||
{
|
||||
CopyShadowMapBuffer.DisableShaderKeyword("STEREO_INSTANCING_ON");
|
||||
}
|
||||
|
||||
BuildCommandBuffer(water, CopyShadowMapBuffer);
|
||||
|
||||
// Restore XR SPI as we cannot rely on remaining pipeline to do it for us.
|
||||
if (camera.stereoEnabled && XRHelpers.IsSinglePass)
|
||||
{
|
||||
CopyShadowMapBuffer.EnableShaderKeyword("STEREO_INSTANCING_ON");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnPostRenderCamera(Camera camera)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
// Do not execute when editor is not active to conserve power and prevent possible leaks.
|
||||
if (!UnityEditorInternal.InternalEditorUtility.isApplicationActive)
|
||||
{
|
||||
CopyShadowMapBuffer?.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!WaterRenderer.IsWithinEditorUpdate)
|
||||
{
|
||||
CopyShadowMapBuffer?.Clear();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
var water = _Water;
|
||||
|
||||
if (water == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Helpers.MaskIncludesLayer(camera.cullingMask, water.Layer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (camera == water.Viewer)
|
||||
{
|
||||
// CBs added to a light are executed for every camera, but the LOD data is only supports a single
|
||||
// camera. Removing the CB after the camera renders restricts the CB to one camera.
|
||||
RemoveCommandBufferFromPrimaryLight();
|
||||
}
|
||||
}
|
||||
|
||||
internal void AddCommandBufferToPrimaryLight()
|
||||
{
|
||||
if (_Light == null || CopyShadowMapBuffer == null) return;
|
||||
_Light.RemoveCommandBuffer(LightEvent.BeforeScreenspaceMask, CopyShadowMapBuffer);
|
||||
_Light.AddCommandBuffer(LightEvent.BeforeScreenspaceMask, CopyShadowMapBuffer);
|
||||
}
|
||||
|
||||
internal void RemoveCommandBufferFromPrimaryLight()
|
||||
{
|
||||
if (_Light == null || CopyShadowMapBuffer == null) return;
|
||||
_Light.RemoveCommandBuffer(LightEvent.BeforeScreenspaceMask, CopyShadowMapBuffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the primary light.
|
||||
/// </summary>
|
||||
@@ -476,7 +369,7 @@ namespace WaveHarmonic.Crest
|
||||
CopyShadowMapBuffer = null;
|
||||
}
|
||||
|
||||
void Update()
|
||||
void Update(CommandBuffer buffer)
|
||||
{
|
||||
// If disabled then we hit a failure state. Try and recover in edit mode by proceeding.
|
||||
if (!_Valid && Application.isPlaying)
|
||||
@@ -502,7 +395,7 @@ namespace WaveHarmonic.Crest
|
||||
return;
|
||||
}
|
||||
|
||||
CopyShadowMapBuffer ??= new() { name = "Crest Shadow Data" };
|
||||
CopyShadowMapBuffer ??= new() { name = WaterRenderer.k_DrawLodData };
|
||||
CopyShadowMapBuffer.Clear();
|
||||
|
||||
FlipBuffers();
|
||||
@@ -514,7 +407,9 @@ namespace WaveHarmonic.Crest
|
||||
if (Application.isPlaying)
|
||||
#endif
|
||||
{
|
||||
Clear(DataTexture);
|
||||
buffer.BeginSample(ID);
|
||||
CoreUtils.SetRenderTarget(buffer, DataTexture, ClearFlag.Color, ClearColor);
|
||||
buffer.EndSample(ID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,6 +417,8 @@ namespace WaveHarmonic.Crest
|
||||
{
|
||||
var isSimulationBuffer = buffer == _Water.SimulationBuffer;
|
||||
|
||||
_IsSimulationBuffer = isSimulationBuffer;
|
||||
|
||||
if (isSimulationBuffer)
|
||||
{
|
||||
var skip = true;
|
||||
@@ -529,101 +426,94 @@ namespace WaveHarmonic.Crest
|
||||
{
|
||||
// If no shadow casters are present, BIRP will not execute the command buffer
|
||||
// leaving outdated shadows in data. We set a flag to determine if the command
|
||||
// buffer was executed.
|
||||
skip = Helpers.GetGlobalBoolean(ShaderIDs.s_ShadowCastersPresent);
|
||||
Helpers.SetGlobalBoolean(ShaderIDs.s_ShadowCastersPresent, false);
|
||||
// buffer was executed. There will a 1-frame delay.
|
||||
skip = Helpers.GetGlobalBoolean(ShaderIDs.s_ShadowPassExecuteLastFrame);
|
||||
Helpers.SetGlobalBoolean(ShaderIDs.s_ShadowPassExecuteLastFrame, false);
|
||||
}
|
||||
|
||||
Update();
|
||||
Update(buffer);
|
||||
|
||||
// Only do a partial update when called by WaterRenderer as we want to execute
|
||||
// with the camera's command buffer (in frame).
|
||||
if (skip) return;
|
||||
if (skip)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: FlipBuffers called elsewhere.
|
||||
|
||||
// Cache the camera for further down.
|
||||
var camera = water.Viewer;
|
||||
|
||||
#pragma warning disable 618
|
||||
using (new ProfilingSample(buffer, isSimulationBuffer ? "Shadows" : "Crest.Shadows"))
|
||||
#pragma warning restore 618
|
||||
if (camera == null)
|
||||
{
|
||||
var jitter = new Vector4
|
||||
(
|
||||
_JitterDiameterSoft,
|
||||
_JitterDiameterHard,
|
||||
_CurrentFrameWeightSoft,
|
||||
_CurrentFrameWeightHard
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
var waterMaterial = _Water.Material;
|
||||
var hasColor = waterMaterial.HasVector(WaterRenderer.ShaderIDs.s_Absorption) && waterMaterial.HasProperty(WaterRenderer.ShaderIDs.s_Scattering);
|
||||
var absorption = hasColor ? waterMaterial.GetVector(WaterRenderer.ShaderIDs.s_Absorption).XYZ() : Vector3.zero;
|
||||
var scattering = hasColor ? ((Vector4)waterMaterial.GetColor(WaterRenderer.ShaderIDs.s_Scattering).MaybeLinear()).XYZ() : Vector3.zero;
|
||||
var sampleAbsorption = _Water.AbsorptionLod.Enabled;
|
||||
var sampleScattering = _Water.ScatteringLod.Enabled;
|
||||
var sampleColor = sampleAbsorption || sampleScattering;
|
||||
base.BuildCommandBuffer(water, buffer);
|
||||
|
||||
if (_DynamicSoftShadows && hasColor && !sampleColor)
|
||||
{
|
||||
// This approximates varying of soft shadowing by volume scattering/absorption density.
|
||||
var extinction = absorption + scattering;
|
||||
var factor = Mathf.Clamp01(Mathf.Min(Mathf.Min(extinction.x, extinction.y), extinction.z) * _SoftJitterExtinctionFactor);
|
||||
jitter.x = (1f - factor) * k_MaximumJitter;
|
||||
}
|
||||
if (RenderPipelineHelper.IsLegacy && !isSimulationBuffer)
|
||||
{
|
||||
buffer.SetGlobalBoolean(ShaderIDs.s_ShadowPassExecuteLastFrame, true);
|
||||
}
|
||||
}
|
||||
|
||||
Shader.SetGlobalFloat(ShaderIDs.s_DynamicSoftShadowsFactor, _DynamicSoftShadows ? _SoftJitterExtinctionFactor : 1f);
|
||||
private protected override void GetSubstepData(float timeToSimulate, out int substeps, out float delta)
|
||||
{
|
||||
substeps = Mathf.FloorToInt(timeToSimulate * _SimulationFrequency);
|
||||
delta = substeps > 0 ? (1f / _SimulationFrequency) : 0f;
|
||||
}
|
||||
|
||||
buffer.BeginSample("Sample");
|
||||
private protected override void SetAdditionalSimulationParameters(PropertyWrapperCompute properties)
|
||||
{
|
||||
base.SetAdditionalSimulationParameters(properties);
|
||||
|
||||
for (var slice = Slices - 1; slice >= 0; slice--)
|
||||
{
|
||||
_RenderMaterial[slice].SetVector(ShaderIDs.s_CenterPos, _Cascades[slice]._SnappedPosition.XNZ(_Water.SeaLevel));
|
||||
var scale = water.CalcLodScale(slice);
|
||||
_RenderMaterial[slice].SetVector(ShaderIDs.s_Scale, new(scale, 1f, scale));
|
||||
_RenderMaterial[slice].SetVector(ShaderIDs.s_JitterDiameters_CurrentFrameWeights, jitter);
|
||||
_RenderMaterial[slice].SetMatrix(ShaderIDs.s_MainCameraProjectionMatrix, GL.GetGPUProjectionMatrix(camera.projectionMatrix, renderIntoTexture: true) * camera.worldToCameraMatrix);
|
||||
_RenderMaterial[slice].SetFloat(ShaderIDs.s_SimDeltaTime, Time.deltaTime);
|
||||
var jitter = new Vector4
|
||||
(
|
||||
_JitterDiameterSoft,
|
||||
_JitterDiameterHard,
|
||||
_CurrentFrameWeightSoft,
|
||||
_CurrentFrameWeightHard
|
||||
);
|
||||
|
||||
// Dynamic Soft Shadows.
|
||||
_RenderMaterial[slice].SetBoolean(ShaderIDs.s_SampleColorMap, _DynamicSoftShadows && sampleColor);
|
||||
if (_DynamicSoftShadows && sampleColor)
|
||||
{
|
||||
_RenderMaterial[slice].SetVector(WaterRenderer.ShaderIDs.s_Absorption, absorption);
|
||||
_RenderMaterial[slice].SetVector(WaterRenderer.ShaderIDs.s_Scattering, scattering);
|
||||
}
|
||||
var waterMaterial = _Water.Surface.Material;
|
||||
var hasColor = waterMaterial != null && waterMaterial.HasVector(WaterRenderer.ShaderIDs.s_Absorption) && waterMaterial.HasProperty(WaterRenderer.ShaderIDs.s_Scattering);
|
||||
var absorption = hasColor ? waterMaterial.GetVector(WaterRenderer.ShaderIDs.s_Absorption).XYZ() : Vector3.zero;
|
||||
var scattering = hasColor ? ((Vector4)waterMaterial.GetColor(WaterRenderer.ShaderIDs.s_Scattering).MaybeLinear()).XYZ() : Vector3.zero;
|
||||
var sampleAbsorption = _Water.AbsorptionLod.Enabled;
|
||||
var sampleScattering = _Water.ScatteringLod.Enabled;
|
||||
var sampleColor = sampleAbsorption || sampleScattering;
|
||||
|
||||
_RenderMaterial[slice].SetTexture(_TextureSourceShaderID, _Targets.Previous(1));
|
||||
if (_DynamicSoftShadows && hasColor && !sampleColor)
|
||||
{
|
||||
// This approximates varying of soft shadowing by volume scattering/absorption density.
|
||||
var extinction = absorption + scattering;
|
||||
var factor = Mathf.Clamp01(Mathf.Min(Mathf.Min(extinction.x, extinction.y), extinction.z) * _SoftJitterExtinctionFactor);
|
||||
jitter.x = (1f - factor) * k_MaximumJitter;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// On recompiles this becomes unset even though we run over the code path to set it again...
|
||||
_RenderMaterial[slice].SetInteger(Lod.ShaderIDs.s_LodIndex, slice);
|
||||
#endif
|
||||
Shader.SetGlobalFloat(ShaderIDs.s_DynamicSoftShadowsFactor, _DynamicSoftShadows ? _SoftJitterExtinctionFactor : 1f);
|
||||
|
||||
if (RenderPipelineHelper.IsLegacy)
|
||||
{
|
||||
// If we are executing the simulation buffer, then we are clearing.
|
||||
_RenderMaterial[slice].SetBoolean(ShaderIDs.s_ClearShadows, isSimulationBuffer);
|
||||
}
|
||||
var camera = _Water.Viewer;
|
||||
|
||||
Helpers.Blit(buffer, DataTexture, _RenderMaterial[slice].Material, depthSlice: slice);
|
||||
}
|
||||
properties.SetVector(ShaderIDs.s_JitterDiameters_CurrentFrameWeights, jitter);
|
||||
properties.SetMatrix(ShaderIDs.s_MainCameraProjectionMatrix, GL.GetGPUProjectionMatrix(camera.projectionMatrix, renderIntoTexture: true) * camera.worldToCameraMatrix);
|
||||
|
||||
buffer.EndSample("Sample");
|
||||
// Dynamic Soft Shadows.
|
||||
properties.SetBoolean(ShaderIDs.s_SampleColorMap, _DynamicSoftShadows && sampleColor);
|
||||
|
||||
// BUG: These draw calls will "leak" and be duplicated before the above blit. They are executed at
|
||||
// the beginning of this CB before any commands are applied.
|
||||
SubmitDraws(buffer, s_Inputs, DataTexture);
|
||||
if (_DynamicSoftShadows && sampleColor)
|
||||
{
|
||||
properties.SetVector(WaterRenderer.ShaderIDs.s_Absorption, absorption);
|
||||
properties.SetVector(WaterRenderer.ShaderIDs.s_Scattering, scattering);
|
||||
}
|
||||
|
||||
// Set the target texture as to make sure we catch the 'pong' each frame
|
||||
Shader.SetGlobalTexture(_TextureShaderID, DataTexture);
|
||||
if (RenderPipelineHelper.IsLegacy)
|
||||
{
|
||||
// If we are executing the simulation buffer, then we are clearing.
|
||||
properties.SetBoolean(ShaderIDs.s_ClearShadows, _IsSimulationBuffer);
|
||||
|
||||
if (RenderPipelineHelper.IsLegacy && !isSimulationBuffer)
|
||||
{
|
||||
buffer.SetGlobalBoolean(ShaderIDs.s_ShadowCastersPresent, true);
|
||||
}
|
||||
properties.SetKeyword(new LocalKeyword(SimulationShader, "SHADOWS_SINGLE_CASCADE"), QualitySettings.shadowCascades == 1);
|
||||
properties.SetKeyword(new LocalKeyword(SimulationShader, "SHADOWS_SPLIT_SPHERES"), QualitySettings.shadowProjection == ShadowProjection.StableFit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user