Skip to content

Commit

Permalink
Fix #1156 Use infinity water depth
Browse files Browse the repository at this point in the history
Fixes incorrect depth values when away from zero, and simplifies a few
things. Caution must be taken as infinity can cause issues.

Water depth sampling had to be moved to the fragment shader, as it had
artifacts from using infinity, possibly from interpolation.

Additionally, needed to adjust values after sampling in fragment.
  • Loading branch information
daleeidd committed Jan 13, 2025
1 parent 473d1c3 commit f8cd841
Show file tree
Hide file tree
Showing 14 changed files with 63 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ namespace Crest
public class LodDataMgrSeaFloorDepth : LodDataMgr
{
// NOTE: Must match CREST_OCEAN_DEPTH_BASELINE in OceanConstants.hlsl.
internal const float k_DepthBaseline = 1_000f;
internal const float k_DepthBaseline = Mathf.Infinity;

public override string SimName => "SeaFloorDepth";
protected override GraphicsFormat RequestedTextureFormat => Settings._allowVaryingWaterLevel ? GraphicsFormat.R32G32_SFloat : GraphicsFormat.R16_SFloat;
protected override bool NeedToReadWriteTextureData => false;
// We want the clear colour to be the min terrain height (-1000m) in X, and sea level offset 0m in Y.
readonly static Color s_nullColor = Color.red * -k_DepthBaseline;
// Lowest possible scene height in X, and sea level offset 0m in Y.
readonly static Color s_nullColor = new Color(-k_DepthBaseline, 0, 0, 0);
static Texture2DArray s_nullTexture;
protected override Texture2DArray NullTexture => s_nullTexture;

Expand Down
4 changes: 1 addition & 3 deletions crest/Assets/Crest/Crest/Scripts/LodData/OceanDepthCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -218,9 +218,7 @@ bool InitObjects(bool updateComponents)
_camDepthCache.transform.parent = transform;
_camDepthCache.transform.localEulerAngles = 90f * Vector3.right;
_camDepthCache.orthographic = true;
_camDepthCache.clearFlags = CameraClearFlags.SolidColor;
// Clear to 'very deep'
_camDepthCache.backgroundColor = Color.white * LodDataMgrSeaFloorDepth.k_DepthBaseline;
_camDepthCache.clearFlags = CameraClearFlags.Depth;
_camDepthCache.enabled = false;
_camDepthCache.allowMSAA = false;
_camDepthCache.allowDynamicResolution = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ public partial class SimSettingsAnimatedWaves : SimSettingsBase
public float AttenuationInShallows => _attenuationInShallows;

[Tooltip("Any water deeper than this will receive full wave strength. The lower the value, the less effective the depth cache will be at attenuating very large waves. Set to the maximum value (1,000) to disable.")]
[SerializeField, Range(1f, LodDataMgrSeaFloorDepth.k_DepthBaseline)]
float _shallowsMaxDepth = LodDataMgrSeaFloorDepth.k_DepthBaseline;
[SerializeField, Range(1f, 1000f)]
float _shallowsMaxDepth = 1000f;
public float MaximumAttenuationDepth => _shallowsMaxDepth;

public enum CollisionSources
Expand Down
36 changes: 27 additions & 9 deletions crest/Assets/Crest/Crest/Shaders/Ocean.shader
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,6 @@ Shader "Crest/Ocean"
// sample shape textures - always lerp between 2 LOD scales, so sample two textures
o.flow_shadow = half4(0.0, 0.0, 0.0, 0.0);

o.lodAlpha_worldXZUndisplaced_oceanDepth.w = CREST_OCEAN_DEPTH_BASELINE;
// Sample shape textures - always lerp between 2 LOD scales, so sample two textures

// Calculate sample weights. params.z allows shape to be faded out (used on last lod to support pop-less scale transitions)
Expand Down Expand Up @@ -410,11 +409,12 @@ Shader "Crest/Ocean"
// Data that needs to be sampled at the displaced position
half seaLevelOffset = 0.0;
o.seaLevelDerivs = 0.0;
half seaDepth = 0;
if (wt_smallerLod > 0.0001)
{
const float3 uv_slice_smallerLodDisp = WorldToUV(o.worldPos.xz, cascadeData0, _LD_SliceIndex);

SampleSeaDepth(_LD_TexArray_SeaFloorDepth, uv_slice_smallerLodDisp, wt_smallerLod, o.lodAlpha_worldXZUndisplaced_oceanDepth.w, seaLevelOffset, cascadeData0, o.seaLevelDerivs);
SampleSeaDepth(_LD_TexArray_SeaFloorDepth, uv_slice_smallerLodDisp, wt_smallerLod, seaDepth, seaLevelOffset, cascadeData0, o.seaLevelDerivs);

#if _SHADOWS_ON
// The minimum sampling weight is lower than others to fix shallow water colour popping.
Expand All @@ -428,7 +428,7 @@ Shader "Crest/Ocean"
{
const float3 uv_slice_biggerLodDisp = WorldToUV(o.worldPos.xz, cascadeData1, _LD_SliceIndex + 1);

SampleSeaDepth(_LD_TexArray_SeaFloorDepth, uv_slice_biggerLodDisp, wt_biggerLod, o.lodAlpha_worldXZUndisplaced_oceanDepth.w, seaLevelOffset, cascadeData1, o.seaLevelDerivs);
SampleSeaDepth(_LD_TexArray_SeaFloorDepth, uv_slice_biggerLodDisp, wt_biggerLod, seaDepth, seaLevelOffset, cascadeData1, o.seaLevelDerivs);

#if _SHADOWS_ON
// The minimum sampling weight is lower than others to fix shallow water colour popping.
Expand Down Expand Up @@ -526,10 +526,6 @@ Shader "Crest/Ocean"
half3 screenPos = input.screenPosXYW;
half2 uvDepth = screenPos.xy / screenPos.z;

#if _CLIPUNDERTERRAIN_ON
clip(input.lodAlpha_worldXZUndisplaced_oceanDepth.w + 2.0);
#endif

half3 view = normalize(_WorldSpaceCameraPos - input.worldPos);

// water surface depth, and underlying scene opaque surface depth
Expand Down Expand Up @@ -563,6 +559,8 @@ Shader "Crest/Ocean"
#if _ALBEDO_ON
half4 albedo = 0.0;
#endif

float seaDepth = 0;
if (wt_smallerLod > 0.001)
{
const float3 uv_slice_smallerLod = WorldToUV(positionXZWSUndisplaced, cascadeData0, _LD_SliceIndex);
Expand All @@ -575,6 +573,10 @@ Shader "Crest/Ocean"
#if _ALBEDO_ON
SampleAlbedo(_LD_TexArray_Albedo, uv_slice_smallerLod, wt_smallerLod, albedo);
#endif

#if defined(_SUBSURFACESHALLOWCOLOUR_ON) || defined(_CLIPUNDERTERRAIN_ON)
SampleSeaDepth(_LD_TexArray_SeaFloorDepth, uv_slice_smallerLod, wt_smallerLod, seaDepth);
#endif
}
if (wt_biggerLod > 0.001)
{
Expand All @@ -588,8 +590,24 @@ Shader "Crest/Ocean"
#if _ALBEDO_ON
SampleAlbedo(_LD_TexArray_Albedo, uv_slice_biggerLod, wt_biggerLod, albedo);
#endif

#if defined(_SUBSURFACESHALLOWCOLOUR_ON) || defined(_CLIPUNDERTERRAIN_ON)
SampleSeaDepth(_LD_TexArray_SeaFloorDepth, uv_slice_biggerLod, wt_biggerLod, seaDepth);
#endif
}

#if _SUBSURFACESHALLOWCOLOUR_ON
seaDepth = min(_SubSurfaceDepthMax, seaDepth);
if (_LD_SliceIndex == ((uint)_SliceCount - 1))
{
seaDepth = lerp(_SubSurfaceDepthMax, seaDepth, wt_smallerLod);
}
#endif

#if _CLIPUNDERTERRAIN_ON
clip(seaDepth + 2.0);
#endif

#if _SUBSURFACESCATTERING_ON
// Extents need the default SSS to avoid popping and not being noticeably different.
if (_LD_SliceIndex == ((uint)_SliceCount - 1))
Expand Down Expand Up @@ -668,7 +686,7 @@ Shader "Crest/Ocean"
// Compute color of ocean - in-scattered light + refracted scene
half3 scatterCol = ScatterColour
(
input.lodAlpha_worldXZUndisplaced_oceanDepth.w,
seaDepth,
shadow.x,
sss,
view,
Expand Down Expand Up @@ -752,7 +770,7 @@ Shader "Crest/Ocean"
// global shadow value.
scatterCol = ScatterColour
(
input.lodAlpha_worldXZUndisplaced_oceanDepth.w,
seaDepth,
UnderwaterShadowSSS(_WorldSpaceCameraPos.xz),
sss,
view,
Expand Down
4 changes: 3 additions & 1 deletion crest/Assets/Crest/Crest/Shaders/OceanConstants.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@

// NOTE: Must match k_DepthBaseline in LodDataMgrSeaFloorDepth.cs.
// Bias ocean floor depth so that default (0) values in texture are not interpreted as shallow and generating foam everywhere
#define CREST_OCEAN_DEPTH_BASELINE 1000.0
#define CREST_OCEAN_DEPTH_BASELINE asfloat(0x7F800000)
#define CREST_MAXIMUM_ATTENUATION_DEPTH 1000.0
#define CREST_FLOAT_MAXIMUM 3.402823466e+38

// Soft shadows is red, hard shadows is green.
#define CREST_SHADOW_INDEX_SOFT 0
Expand Down
17 changes: 10 additions & 7 deletions crest/Assets/Crest/Crest/Shaders/OceanHelpersNew.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -124,23 +124,25 @@ void SampleAlbedo(in Texture2DArray i_oceanAlbedoSampler, in float3 i_uv_slice,

void SampleSeaDepth(in Texture2DArray i_oceanDepthSampler, in float3 i_uv_slice, in float i_wt, inout half io_oceanDepth)
{
const half2 terrainHeight_seaLevelOffset = i_oceanDepthSampler.SampleLevel(LODData_linear_clamp_sampler, i_uv_slice.xyz, 0.0).xy;
half2 terrainHeight_seaLevelOffset = i_oceanDepthSampler.SampleLevel(LODData_linear_clamp_sampler, i_uv_slice.xyz, 0.0).xy;
terrainHeight_seaLevelOffset.x = max(terrainHeight_seaLevelOffset.x, -CREST_FLOAT_MAXIMUM);
const half waterDepth = _OceanCenterPosWorld.y - terrainHeight_seaLevelOffset.x + terrainHeight_seaLevelOffset.y;
io_oceanDepth += i_wt * (waterDepth - CREST_OCEAN_DEPTH_BASELINE);
io_oceanDepth += i_wt * waterDepth;
}

void SampleSingleSeaDepth(Texture2DArray i_oceanDepthSampler, float3 i_uv_slice, inout half io_oceanDepth, inout half io_seaLevelOffset)
{
const half2 terrainHeight_seaLevelOffset = i_oceanDepthSampler.SampleLevel(LODData_linear_clamp_sampler, i_uv_slice, 0.0).xy;
const half waterDepth = _OceanCenterPosWorld.y - terrainHeight_seaLevelOffset.x + terrainHeight_seaLevelOffset.y;
io_oceanDepth = waterDepth - CREST_OCEAN_DEPTH_BASELINE;
half2 terrainHeight_seaLevelOffset = i_oceanDepthSampler.SampleLevel(LODData_linear_clamp_sampler, i_uv_slice, 0.0).xy;
terrainHeight_seaLevelOffset.x = max(terrainHeight_seaLevelOffset.x, -CREST_FLOAT_MAXIMUM);
io_oceanDepth = _OceanCenterPosWorld.y - terrainHeight_seaLevelOffset.x + terrainHeight_seaLevelOffset.y;
io_seaLevelOffset = terrainHeight_seaLevelOffset.y;
}

void SampleSeaDepth(in Texture2DArray i_oceanDepthSampler, in float3 i_uv_slice, in float i_wt, inout half io_oceanDepth, inout half io_seaLevelOffset, const CascadeParams i_cascadeParams, inout float2 io_seaLevelDerivs)
{
const half2 terrainHeight_seaLevelOffset = i_oceanDepthSampler.SampleLevel( LODData_linear_clamp_sampler, i_uv_slice, 0.0 ).xy;
io_oceanDepth += i_wt * (_OceanCenterPosWorld.y - terrainHeight_seaLevelOffset.x + terrainHeight_seaLevelOffset.y - CREST_OCEAN_DEPTH_BASELINE);
half2 terrainHeight_seaLevelOffset = i_oceanDepthSampler.SampleLevel( LODData_linear_clamp_sampler, i_uv_slice, 0.0 ).xy;
terrainHeight_seaLevelOffset.x = max(terrainHeight_seaLevelOffset.x, -CREST_FLOAT_MAXIMUM);
io_oceanDepth += i_wt * (_OceanCenterPosWorld.y - terrainHeight_seaLevelOffset.x + terrainHeight_seaLevelOffset.y);
io_seaLevelOffset += i_wt * terrainHeight_seaLevelOffset.y;

{
Expand All @@ -159,6 +161,7 @@ void SampleSeaDepth(in Texture2DArray i_oceanDepthSampler, in float3 i_uv_slice,
void SampleTerrainHeight(const Texture2DArray i_texture, const float3 i_uv, inout half io_terrainHeight)
{
io_terrainHeight = i_texture.SampleLevel(LODData_linear_clamp_sampler, i_uv, 0.0).x;
io_terrainHeight = max(io_terrainHeight, -CREST_FLOAT_MAXIMUM);
}

void SampleSeaLevelOffset(in Texture2DArray i_oceanDepthSampler, in float3 i_uv_slice, in float i_wt, inout half io_seaLevelOffset)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,12 @@ Shader "Crest/Inputs/Shape Waves/Sample Spectrum"

half GetAttenuationInShallowsWeight(const Texture2DArray i_texture, const float3 i_uv)
{
const half2 terrainHeight_seaLevelOffset = i_texture.SampleLevel(LODData_linear_clamp_sampler, i_uv, 0.0).xy;
half2 terrainHeight_seaLevelOffset = i_texture.SampleLevel(LODData_linear_clamp_sampler, i_uv, 0.0).xy;
terrainHeight_seaLevelOffset.x = max(terrainHeight_seaLevelOffset.x, -CREST_FLOAT_MAXIMUM);
const half depth = _OceanCenterPosWorld.y - terrainHeight_seaLevelOffset.x + terrainHeight_seaLevelOffset.y;
// Attenuate if depth is less than half of the average wavelength.
half weight = saturate(2.0 * depth / _AverageWavelength);
if (_MaximumAttenuationDepth < CREST_OCEAN_DEPTH_BASELINE)
if (_MaximumAttenuationDepth < CREST_MAXIMUM_ATTENUATION_DEPTH)
{
weight = lerp(weight, 1.0, saturate(depth / _MaximumAttenuationDepth));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ CBUFFER_END
half3 ComputeGerstner(float2 worldPosXZ, float3 uv_slice)
{
// sample ocean depth (this render target should 1:1 match depth texture, so UVs are trivial)
const half2 terrainHeight_seaLevelOffset = _LD_TexArray_SeaFloorDepth.SampleLevel(LODData_linear_clamp_sampler, uv_slice, 0.0).xy;
half2 terrainHeight_seaLevelOffset = _LD_TexArray_SeaFloorDepth.SampleLevel(LODData_linear_clamp_sampler, uv_slice, 0.0).xy;
terrainHeight_seaLevelOffset.x = max(terrainHeight_seaLevelOffset.x, -CREST_FLOAT_MAXIMUM);
const half depth = _OceanCenterPosWorld.y - terrainHeight_seaLevelOffset.x + terrainHeight_seaLevelOffset.y;

// Preferred wave directions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,12 @@ Shader "Hidden/Crest/Inputs/Animated Waves/Gerstner Global"
float wt = _Weight;

// Attenuate if depth is less than half of the average wavelength
const half2 terrainHeight_seaLevelOffset =
half2 terrainHeight_seaLevelOffset =
_LD_TexArray_SeaFloorDepth.SampleLevel(LODData_linear_clamp_sampler, float3(input.uv_uvWaves.xy, _LD_SliceIndex), 0.0).xy;
terrainHeight_seaLevelOffset.x = max(terrainHeight_seaLevelOffset.x, -CREST_FLOAT_MAXIMUM);
const half depth = _OceanCenterPosWorld.y - terrainHeight_seaLevelOffset.x + terrainHeight_seaLevelOffset.y;
half depth_wt = saturate(2.0 * depth / _AverageWavelength);
if (_MaximumAttenuationDepth < CREST_OCEAN_DEPTH_BASELINE)
if (_MaximumAttenuationDepth < CREST_MAXIMUM_ATTENUATION_DEPTH)
{
depth_wt = lerp(depth_wt, 1.0, saturate(depth / _MaximumAttenuationDepth));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,11 @@ Shader "Crest/Inputs/Animated Waves/Gerstner Geometry"
float wt = input.invNormDistToShoreline_weight.y;

// Attenuate if depth is less than half of the average wavelength
const half2 terrainHeight_seaLevelOffset = _LD_TexArray_SeaFloorDepth.SampleLevel(LODData_linear_clamp_sampler, input.uv_slice, 0.0).xy;
half2 terrainHeight_seaLevelOffset = _LD_TexArray_SeaFloorDepth.SampleLevel(LODData_linear_clamp_sampler, input.uv_slice, 0.0).xy;
terrainHeight_seaLevelOffset.x = max(terrainHeight_seaLevelOffset.x, -CREST_FLOAT_MAXIMUM);
const half depth = _OceanCenterPosWorld.y - terrainHeight_seaLevelOffset.x + terrainHeight_seaLevelOffset.y;
half depth_wt = saturate(2.0 * depth / _AverageWavelength);
if (_MaximumAttenuationDepth < CREST_OCEAN_DEPTH_BASELINE)
if (_MaximumAttenuationDepth < CREST_MAXIMUM_ATTENUATION_DEPTH)
{
depth_wt = lerp(depth_wt, 1.0, saturate(depth / _MaximumAttenuationDepth));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ void UpdateDynWaves(uint3 id : SV_DispatchThreadID)

const float3 uv_slice = float3(input_uv, sliceIndex);

const float2 terrainHeight_seaLevelOffset = _LD_TexArray_SeaFloorDepth.SampleLevel(LODData_linear_clamp_sampler, uv_slice, 0.0).xy;
float2 terrainHeight_seaLevelOffset = _LD_TexArray_SeaFloorDepth.SampleLevel(LODData_linear_clamp_sampler, uv_slice, 0.0).xy;
terrainHeight_seaLevelOffset.x = max(terrainHeight_seaLevelOffset.x, -CREST_FLOAT_MAXIMUM);
const float waterDepth = _OceanCenterPosWorld.y - terrainHeight_seaLevelOffset.x + terrainHeight_seaLevelOffset.y;

// Wave reflections off geometry.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ void UpdateFoam(uint3 id : SV_DispatchThreadID)

// Add foam in shallow water. use the displaced position to ensure we add foam where world objects are.
const float3 uv_slice_displaced = WorldToUV(worldPosXZ + disp.xz, cascadeData, sliceIndex);
const half2 terrainHeight_seaLevelOffset = _LD_TexArray_SeaFloorDepth.SampleLevel(LODData_linear_clamp_sampler, uv_slice_displaced, 0.0).xy;
half2 terrainHeight_seaLevelOffset = _LD_TexArray_SeaFloorDepth.SampleLevel(LODData_linear_clamp_sampler, uv_slice_displaced, 0.0).xy;
terrainHeight_seaLevelOffset.x = max(terrainHeight_seaLevelOffset.x, -CREST_FLOAT_MAXIMUM);
const half signedOceanDepth = _OceanCenterPosWorld.y - terrainHeight_seaLevelOffset.x + terrainHeight_seaLevelOffset.y + disp.y;
foam += _ShorelineFoamStrength * simDeltaTime * saturate(1.0 - signedOceanDepth / _ShorelineFoamMaxDepth);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ Shader "Crest/Underwater Curtain"
const half shadow = 1.0;
const half sss = 0.0;

half seaFloorDepth = CREST_OCEAN_DEPTH_BASELINE;
half seaFloorDepth = 0.0;
#if _SUBSURFACESHALLOWCOLOUR_ON
{
// compute scatter colour from cam pos. two scenarios this can be called:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ half3 ApplyUnderwaterEffect
}
#endif // _SHADOWS_ON

half seaFloorDepth = CREST_OCEAN_DEPTH_BASELINE;
half seaFloorDepth = 0.0;
#if _SUBSURFACESHALLOWCOLOUR_ON
{
// compute scatter colour from cam pos. two scenarios this can be called:
Expand Down

0 comments on commit f8cd841

Please sign in to comment.