升级水插件
This commit is contained in:
@@ -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