升级6.4.升级水,升级天气

This commit is contained in:
2026-04-05 00:26:54 +08:00
parent 63bc9b5536
commit 5f7cbfb713
635 changed files with 34718 additions and 22567 deletions

View File

@@ -63,7 +63,7 @@ Shader "Crest/Inputs/Albedo/Color"
float3 positionWS = mul(unity_ObjectToWorld, float4(input.vertex, 1.0)).xyz;
positionWS.xz -= _Crest_DisplacementAtInputPosition.xz;
output.vertex = mul(UNITY_MATRIX_VP, float4(positionWS, 1.0));
output.uv = input.uv;
output.uv = TRANSFORM_TEX(input.uv, _Crest_Texture);
output.color = input.color;
return output;
}

View File

@@ -90,7 +90,7 @@ Shader "Crest/Inputs/Dynamic Waves/Add Bump"
y = pow(y, 0.05);
y *= _Crest_Amplitude;
y /= g_Crest_LodCount;
y /= (float)g_Crest_LodCount;
// Feather edges to reduce streaking without introducing reflections.
y *= FeatherWeightFromUV(input.uv, 0.1);
@@ -107,4 +107,5 @@ Shader "Crest/Inputs/Dynamic Waves/Add Bump"
ENDCG
}
}
CustomEditor "WaveHarmonic.Crest.Editor.CustomShaderGUI"
}

View File

@@ -1,6 +1,8 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
#pragma exclude_renderers glcore gles3
#pragma kernel CrestExecute
#include "HLSLSupport.cginc"

View File

@@ -1,6 +1,8 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
#pragma exclude_renderers glcore gles3
#pragma kernel CrestTransferWaves
#pragma multi_compile_local __ d_Texture d_TextureBlend
@@ -11,6 +13,7 @@
#include "HLSLSupport.cginc"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Utility/Filtering.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Macros.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Constants.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Globals.hlsl"
@@ -23,6 +26,7 @@ Texture2DArray _Crest_WaveBuffer;
RWTexture2DArray<float4> _Crest_Target;
CBUFFER_START(CrestPerMaterial)
float _Crest_WaveBufferAttenuation[k_Crest_WaveOctaveCount];
float4 _Crest_WaveBufferParameters[MAX_LOD_COUNT];
float2 _Crest_AxisX;
float _Crest_Weight;
@@ -32,12 +36,15 @@ float _Crest_RespectShallowWaterAttenuation;
float _Crest_MaximumAttenuationDepth;
float _Crest_WaveResolutionMultiplier;
float _Crest_TransitionalWavelengthThreshold;
uint _Crest_Resolution;
bool _Crest_SeaLevelOnly;
// Texture
#if d_Texture
float2 _Crest_TextureSize;
float2 _Crest_TexturePosition;
float2 _Crest_TextureRotation;
float2 _Crest_Multiplier;
bool _Crest_NegativeValues;
int _Crest_Blend;
#endif
@@ -60,6 +67,8 @@ void TransferWaves(uint3 id)
const uint last = parameters.y;
const half transition = parameters.w;
const uint2 resolution = uint2(_Crest_Resolution, _Crest_Resolution);
#if !d_TextureBlend
// Additive only. All wavelengths filtered out for this LOD so nothing to do.
if (parameters.x < 0 || parameters.y < 0)
@@ -95,7 +104,7 @@ void TransferWaves(uint3 id)
float2 axis; float axisLength = 0.0; float t = 0.0;
float2 axisX0 = 0.0; float2 axisX1 = 0.0; float2 axisZ0 = 0.0; float2 axisZ1 = 0.0;
{
axis = _Crest_Texture.SampleLevel(LODData_linear_clamp_sampler, uvPainted, 0).xy;
axis = _Crest_Texture.SampleLevel(LODData_linear_clamp_sampler, uvPainted, 0).xy * _Crest_Multiplier;
if (!_Crest_NegativeValues)
{
@@ -154,11 +163,12 @@ void TransferWaves(uint3 id)
axisZ1.x = -axisX1.y; axisZ1.y = axisX1.x;
}
#else
const float2 positionWaves = float2(dot(positionWS, _Crest_AxisX), dot(positionWS, float2(-_Crest_AxisX.y, _Crest_AxisX.x)));
#endif // d_Texture
const half depth = Cascade::MakeDepth(slice0).SampleSignedDepthFromSeaLevel(positionWS) +
Cascade::MakeLevel(slice0).SampleLevel(positionWS);
const half level = Cascade::MakeLevel(slice0).SampleLevel(positionWS);
const half depth = Cascade::MakeDepth(slice0).SampleSignedDepthFromSeaLevel(positionWS) + level;
half3 _displacement = 0.0;
@@ -198,8 +208,7 @@ void TransferWaves(uint3 id)
weight = lerp(weight, 1.0, saturate(depth / _Crest_MaximumAttenuationDepth));
}
const float attenuationAmount = _Crest_AttenuationInShallows * _Crest_RespectShallowWaterAttenuation;
const float attenuationAmount = _Crest_AttenuationInShallows * _Crest_RespectShallowWaterAttenuation * _Crest_WaveBufferAttenuation[i];
attenuation = attenuationAmount * weight + (1.0 - attenuationAmount);
}
@@ -217,8 +226,8 @@ void TransferWaves(uint3 id)
const float2 uv1 = float2(dot(positionScaledWS, axisX1), dot(positionScaledWS, axisZ1));
// Sample displacement, rotate into frame.
float3 displacement0 = _Crest_WaveBuffer.SampleLevel(sampler_Crest_linear_repeat, float3(uv0, waveBufferIndex), 0).xyz;
float3 displacement1 = _Crest_WaveBuffer.SampleLevel(sampler_Crest_linear_repeat, float3(uv1, waveBufferIndex), 0).xyz;
const float3 displacement0 = Utility::SampleBicubicRepeat(_Crest_WaveBuffer, uv0, resolution, waveBufferIndex).xyz;
const float3 displacement1 = Utility::SampleBicubicRepeat(_Crest_WaveBuffer, uv1, resolution, waveBufferIndex).xyz;
float3 displacement = lerp(displacement0, displacement1, t);
displacement.xz = displacement.x * axis + displacement.z * float2(-axis.y, axis.x);
@@ -227,7 +236,9 @@ void TransferWaves(uint3 id)
#else // !d_Texture
// Sample displacement, rotate into frame defined by global wind direction.
half3 displacement = _Crest_WaveBuffer.SampleLevel(sampler_Crest_linear_repeat, float3(positionWaves / waveBufferSize, waveBufferIndex), 0).xyz;
// Hardware bilinear produces small noise artifacts. Custom bilinear solves that,
// but we still get texel artifacts that show up in normals, so use bicubic.
float3 displacement = Utility::SampleBicubicRepeat(_Crest_WaveBuffer, positionWaves / waveBufferSize, resolution, waveBufferIndex).xyz;
displacement.xz = displacement.x * _Crest_AxisX + displacement.z * float2(-_Crest_AxisX.y, _Crest_AxisX.x);
_displacement += displacement * weight;
#endif // d_Texture
@@ -239,6 +250,13 @@ void TransferWaves(uint3 id)
_Crest_Target[id] *= 1.0 - saturate(alpha);
#endif
#if !d_Texture
if (_Crest_SeaLevelOnly)
{
_displacement *= saturate(1.0 - abs(level));
}
#endif
// Always write full alpha so textures show up in previews.
_Crest_Target[id] += float4(_displacement, 1.0);
}

View File

@@ -1,6 +1,8 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
#pragma exclude_renderers glcore gles3
#pragma kernel CrestExecute
#pragma multi_compile_local d_Sphere d_Cube d_Rectangle

View File

@@ -3,6 +3,8 @@
// Adds clipping from a provided texture. Used by Painted and Texture input modes.
#pragma exclude_renderers glcore gles3
#pragma kernel CrestExecute
#include "HLSLSupport.cginc"

View File

@@ -6,6 +6,8 @@
// afterwards. It is converted to world-space in another shader before writing into
// the LOD data.
#pragma exclude_renderers glcore gles3
#pragma kernel CrestCopy
#pragma kernel CrestFill
@@ -17,7 +19,7 @@
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Globals.hlsl"
Texture2D<float> _CamDepthBuffer;
RWTexture2D<float2> _Crest_Target;
RWTexture2D<m_Float2> _Crest_Target;
#if d_Crest_BackFaceInclusion
Texture2D<float> _Crest_CameraDepthBufferBackfaces;

View File

@@ -5,6 +5,8 @@
// from an ODC, then they are in object-space and are converted to world-space as
// the LOD data stores world-space height.
#pragma exclude_renderers glcore gles3
#pragma kernel CrestExecute
#pragma multi_compile_local __ d_CrestSDF
@@ -22,14 +24,14 @@
#if d_CrestSDF
#undef m_CrestType
#define m_CrestType float2
#define m_CrestType m_Float2
#endif
Texture2D<m_CrestType> _Crest_Texture;
RWTexture2DArray<m_CrestType> _Crest_Target;
CBUFFER_START(CrestInputTexture)
float2 _Crest_Multiplier;
m_CrestType _Crest_Multiplier;
float2 _Crest_TextureSize;
float2 _Crest_TexturePosition;
float2 _Crest_TextureRotation;

View File

@@ -3,6 +3,8 @@
// Adds flow from a provided texture. Used by Painted and Texture input modes.
#pragma exclude_renderers glcore gles3
#pragma kernel CrestExecute
#include "HLSLSupport.cginc"
@@ -15,7 +17,7 @@
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Cascade.hlsl"
Texture2D _Crest_Texture;
RWTexture2DArray<float2> _Crest_Target;
RWTexture2DArray<m_Float2> _Crest_Target;
CBUFFER_START(CrestPerMaterial)
int _Crest_Blend;
@@ -62,7 +64,8 @@ void Execute(uint3 id)
}
const float2 target = _Crest_Target[id];
_Crest_Target[id] = Blend(_Crest_Blend, weight, 1.0, source, target);
const float2 result = Blend(_Crest_Blend, weight, 1.0, source, target);
_Crest_Target[id] = m_Float2FromFloat2(result);
}
m_CrestNameSpaceEnd

View File

@@ -3,6 +3,8 @@
// Adds foam from a provided texture. Used by Painted and Texture input modes.
#pragma exclude_renderers glcore gles3
#pragma kernel CrestExecute
#include "HLSLSupport.cginc"

View File

@@ -4,6 +4,8 @@
// An implementation of the Jump Flood algorithm by Rong and Tan
// Source: https://www.comp.nus.edu.sg/~tants/jfa.html
#pragma exclude_renderers glcore gles3
#pragma kernel CrestInitialize
#pragma kernel CrestExecute
#pragma kernel CrestApply
@@ -27,13 +29,13 @@ float _Crest_WaterLevel;
CBUFFER_END
// Holds scene depth for initialization.
Texture2D<float2> _Crest_Source;
RWTexture2D<float2> _Crest_Target;
Texture2D<m_Float2> _Crest_Source;
RWTexture2D<m_Float2> _Crest_Target;
// Setting this to zero means that geometry at exactly the origin won't be handled
// gracefully - but it would only affect a single-pixel in the worst-case and would
// doubtfully be noticable anyway. Use infinity instead.
#define m_CrestUninitializedPosition float2(m_Crest_PositiveInfinity, m_Crest_PositiveInfinity)
#define m_CrestUninitializedPosition m_Float2Constructor(m_Crest_PositiveInfinity, m_Crest_PositiveInfinity)
#if d_Crest_Inverted
#define m_DepthCheck depth > 0.0
@@ -62,11 +64,11 @@ void Initialize(const uint3 id)
#ifndef d_Crest_Standalone
// Add height offset.
uint slice0; uint slice1; float alpha;
PosToSliceIndices(position, 0, g_Crest_LodCount - 1, g_Crest_WaterScale, slice0, slice1, alpha);
PositionToSliceIndices(position, 0, g_Crest_LodCount - 1, g_Crest_WaterScale, slice0, slice1, alpha);
depth += lerp(Cascade::MakeLevel(slice0).SampleLevel(position), Cascade::MakeLevel(slice1).SampleLevel(position), alpha);
#endif
_Crest_Target[id.xy] = m_DepthCheck ? position : m_CrestUninitializedPosition;
_Crest_Target[id.xy] = m_DepthCheck ? m_Float2FromFloat2(position) : m_CrestUninitializedPosition;
}
void Execute(const uint3 id)
@@ -111,7 +113,7 @@ void Execute(const uint3 id)
}
}
_Crest_Target[id.xy] = nearest;
_Crest_Target[id.xy] = m_Float2FromFloat2(nearest);
}
void Apply(const uint3 id)
@@ -125,7 +127,7 @@ void Apply(const uint3 id)
#ifndef d_Crest_Standalone
// Get depth including height offset.
uint slice0; uint slice1; float alpha;
PosToSliceIndices(position, 0, g_Crest_LodCount - 1, g_Crest_WaterScale, slice0, slice1, alpha);
PositionToSliceIndices(position, 0, g_Crest_LodCount - 1, g_Crest_WaterScale, slice0, slice1, alpha);
depth += lerp(Cascade::MakeLevel(slice0).SampleLevel(position), Cascade::MakeLevel(slice1).SampleLevel(position), alpha);
#endif
@@ -144,7 +146,7 @@ void Apply(const uint3 id)
result.y = distance;
_Crest_Target[id.xy] = result;
_Crest_Target[id.xy] = m_Float2FromFloat2(result);
}
m_CrestNameSpaceEnd

View File

@@ -3,6 +3,8 @@
// Adds height from a provided texture. Used by Painted and Texture input modes.
#pragma exclude_renderers glcore gles3
#pragma kernel CrestExecute
#pragma multi_compile_local __ d_CatmullRom
@@ -27,7 +29,7 @@ float _Crest_Multiplier;
float2 _Crest_TextureSize;
float2 _Crest_TexturePosition;
float2 _Crest_TextureRotation;
float2 _Crest_Resolution;
float2 _Crest_TextureResolution;
CBUFFER_END
m_CrestNameSpace
@@ -49,7 +51,7 @@ void Execute(uint3 id)
}
#if d_CatmullRom
const float source = Utility::SampleTextureCatmullRom(_Crest_Texture, LODData_linear_clamp_sampler, uv, _Crest_Resolution)
const float source = Utility::SampleTextureCatmullRom(_Crest_Texture, LODData_linear_clamp_sampler, uv, _Crest_TextureResolution)
#else
const float source = _Crest_Texture.SampleLevel(LODData_linear_clamp_sampler, uv, 0.0)
#endif

View File

@@ -1,6 +1,8 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
#pragma exclude_renderers glcore gles3
#pragma kernel CrestExecute
#include "HLSLSupport.cginc"

View File

@@ -1,6 +1,8 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
#pragma exclude_renderers glcore gles3
#pragma kernel CrestExecute
#include "HLSLSupport.cginc"
@@ -12,7 +14,7 @@
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/InputsDriven.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Cascade.hlsl"
RWTexture2DArray<float2> _Crest_Target;
RWTexture2DArray<m_Float2> _Crest_Target;
CBUFFER_START(CrestPerWaterInput)
float3 _Crest_Position;
@@ -116,7 +118,7 @@ void Execute(uint3 id)
// Helps interaction to work at different scales
acceleration /= minimumWavelength;
_Crest_Target[id] = float2(_Crest_Target[id].x, _Crest_Target[id].y + acceleration * _Crest_SimDeltaTime);
_Crest_Target[id] = m_Float2Constructor(_Crest_Target[id].x, _Crest_Target[id].y + acceleration * _Crest_SimDeltaTime);
}
m_CrestNameSpaceEnd

View File

@@ -110,7 +110,7 @@ Shader "Crest/Inputs/All/Scale"
half4 Frag(Varyings input) : SV_Target
{
#if d_Texture
float scale = _Crest_Texture.Sample(sampler_Crest_Texture, input.uv).r;
float scale = _Crest_Texture.Sample(sampler_Crest_Texture, TRANSFORM_TEX(input.uv, _Crest_Texture)).r;
#else
float scale = _Crest_Scale;
#endif

View File

@@ -50,6 +50,7 @@ Shader "Crest/Inputs/Shape Waves/Add From Geometry"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Helpers.hlsl"
Texture2DArray _Crest_WaveBuffer;
SamplerState sampler_Crest_linear_repeat;
CBUFFER_START(CrestPerWaterInput)
float _Crest_RespectShallowWaterAttenuation;

View File

@@ -1,6 +1,8 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
#pragma exclude_renderers glcore gles3
#pragma kernel CrestPackLevel
#include "HLSLSupport.cginc"

View File

@@ -1,6 +1,8 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
#pragma exclude_renderers glcore gles3
#pragma kernel CrestQueryDisplacement d_CrestDisplacement
#pragma kernel CrestQueryFlow d_CrestFlow
#pragma kernel CrestQueryDepth d_CrestDepth
@@ -40,13 +42,13 @@ RWStructuredBuffer<float3> _Crest_Target;
m_CrestNameSpace
float3 Compute(const float2 i_Position, const float i_MinimumSlice, const float i_BaseScale)
float3 Compute(const float2 i_Position, const uint i_MinimumSlice, const float i_BaseScale)
{
// Do not use last slice - this is a 'transition' slice used to cross-fade waves
// between LOD resolutions to avoid pops. That being said, this will have clamped
// samples leading to objects floating on waves that do not exist.
uint slice0, slice1; float alpha;
PosToSliceIndices(i_Position, i_MinimumSlice, g_Crest_LodCount - 2.0, i_BaseScale, slice0, slice1, alpha);
PositionToSliceIndices(i_Position, i_MinimumSlice, g_Crest_LodCount - 2, i_BaseScale, slice0, slice1, alpha);
const Cascade cascade0 = Cascade::d_CrestMake(slice0);
const Cascade cascade1 = Cascade::d_CrestMake(slice1);
@@ -64,15 +66,9 @@ float3 Compute(const float2 i_Position, const float i_MinimumSlice, const float
void Query(const uint3 id)
{
const float3 data = _Crest_QueryPositions_MinimumGridSizes[id.x];
const float minimumGridSize = data.z;
const uint minimumSlice = data.z;
float2 position = data.xy;
const float gridSizeSlice0 = Cascade::d_CrestMake(0)._Texel;
// Displacements should not utilize the last slice which is used for transitioning
// waves between sampling resolutions. While it might be ok to use the last slice
// for other targets, we avoid using it to be consistent with displacements.
const float minimumSlice = clamp(floor(log2(max(minimumGridSize / gridSizeSlice0, 1.0))), 0.0, g_Crest_LodCount - 2.0);
#if d_CrestDisplacement
// Perform iteration to invert the displacement vector field - find position that displaces to query position,
// and return displacement at that point.

View File

@@ -3,6 +3,8 @@
// Merged into Query.compute.
#pragma exclude_renderers glcore gles3
#pragma kernel CrestExecute
[numthreads(1, 1, 1)]
void CrestExecute(uint3 id : SV_DispatchThreadID) { }

View File

@@ -3,6 +3,8 @@
// Merged into Query.compute.
#pragma exclude_renderers glcore gles3
#pragma kernel CrestExecute
[numthreads(1, 1, 1)]
void CrestExecute(uint3 id : SV_DispatchThreadID) { }

View File

@@ -1,91 +1,48 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
// Compute shader to perform combine of displacements. Reads and writes to texture array which saves
// needing to do ping pong of render targets. Unfortunately reading/writing float4s is not supported
// on pre-DX11.3 hardware (aka typed UAV loads), so this path is not the default, for now..
#pragma exclude_renderers glcore gles3
#pragma kernel ShapeCombine
#pragma kernel ShapeCombine_DISABLE_COMBINE _DISABLE_COMBINE
#pragma kernel ShapeCombine_FLOW_ON _FLOW_ON
#pragma kernel ShapeCombine_FLOW_ON_DISABLE_COMBINE _FLOW_ON _DISABLE_COMBINE
#pragma kernel ShapeCombine_DYNAMIC_WAVE_SIM_ON _DYNAMIC_WAVE_SIM_ON
#pragma kernel ShapeCombine_DYNAMIC_WAVE_SIM_ON_DISABLE_COMBINE _DYNAMIC_WAVE_SIM_ON _DISABLE_COMBINE
#pragma kernel ShapeCombine_FLOW_ON_DYNAMIC_WAVE_SIM_ON _FLOW_ON _DYNAMIC_WAVE_SIM_ON
#pragma kernel ShapeCombine_FLOW_ON_DYNAMIC_WAVE_SIM_ON_DISABLE_COMBINE _FLOW_ON _DYNAMIC_WAVE_SIM_ON _DISABLE_COMBINE
#pragma kernel ShapeCombineDynamicWaves
#pragma kernel ShapeCombineDynamicWaves_DISABLE_COMBINE _DISABLE_COMBINE
#pragma kernel ShapeCombineCopyDynamicWaves
#pragma kernel CrestShapeCombineAnimatedWaves
#pragma kernel CrestShapeCopyAnimatedWaves
#pragma kernel CrestShapeCombineDynamicWaves d_CombineDynamicWaves
#pragma multi_compile_local _ d_Combine
#pragma multi_compile_local _ d_DynamicWaves
#pragma multi_compile _ CREST_FLOW_ON_INTERNAL
#if d_CombineDynamicWaves
#define d_DynamicWaves 1
#endif
#include "HLSLSupport.cginc"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Keywords.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Macros.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Constants.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Globals.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/InputsDriven.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Cascade.hlsl"
#if d_Combine
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Utility/Filtering.hlsl"
#endif
#if d_Crest_FlowLod
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Flow.hlsl"
#endif
float _Crest_HorizontalDisplace;
float _Crest_DisplaceClamp;
Texture2DArray _Crest_WaveBuffer;
RWTexture2DArray<float4> _Crest_Target;
RWTexture2DArray<float4> _Crest_DynamicWavesTarget;
RWTexture2DArray<float4> _Crest_AnimatedWavesTarget;
m_CrestNameSpace
void Flow(const float texel, out float2 offsets, out float2 weights)
void ShapeCombine(uint3 id)
{
const float period = max(3.0 * texel, 1.0);
const float half_period = period / 2.0;
offsets = fmod(float2(g_Crest_Time, g_Crest_Time + half_period), period);
weights.x = offsets.x / half_period;
if (weights.x > 1.0) weights.x = 2.0 - weights.x;
weights.y = 1.0 - weights.x;
}
void SampleDisplacementsCompute(
in RWTexture2DArray<float4> i_dispSampler,
in float i_resolution, in float3 i_uv_slice,
in float i_wt, inout float3 io_worldPos
) {
// NOTE: We have to roll our own bilinear filter in Compute shaders when
// reading from a RWTexture. The documentation below explains how SRV
// and UAV mappings of the same texture cannot exist at the same time.
// https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/sm5-object-rwtexture2d
// Convert from UV to coordinates
const float2 pixelCoord = i_uv_slice.xy * i_resolution;
// Make relative to pixel centers
float2 pixelCoordCenters = pixelCoord - 0.5;
// Clamp from below and above (desired?)
pixelCoordCenters = clamp(pixelCoordCenters, 0.0, i_resolution - 1.0);
// Compute integral and fractional parts
const uint2 pixelCoordCentersBotLeft = floor(pixelCoordCenters);
const uint sliceIndex = i_uv_slice.z;
const float2 pixelCoordCentersFrac = frac(pixelCoordCenters);
const half4 dataBotLeft = i_dispSampler[uint3(pixelCoordCentersBotLeft, sliceIndex)];
const half4 dataBotRight = i_dispSampler[uint3(pixelCoordCentersBotLeft + uint2(1, 0), sliceIndex)];
const half4 dataTopLeft = i_dispSampler[uint3(pixelCoordCentersBotLeft + uint2(0, 1), sliceIndex)];
const half4 dataTopRight = i_dispSampler[uint3(pixelCoordCentersBotLeft + uint2(1, 1), sliceIndex)];
const float4 dataLerped = lerp(
lerp(dataBotLeft, dataBotRight, pixelCoordCentersFrac.x),
lerp(dataTopLeft, dataTopRight, pixelCoordCentersFrac.x),
pixelCoordCentersFrac.y
);
io_worldPos += i_wt * dataLerped.xyz;
}
void ShapeCombineBase(uint3 id)
{
const uint slice0 = _Crest_LodIndex;
const uint slice0 = id.z;
const Cascade cascade = Cascade::MakeAnimatedWaves(slice0);
const float3 uv = cascade.IDToUV(id.xy);
@@ -93,87 +50,68 @@ void ShapeCombineBase(uint3 id)
float3 result = 0.0;
#if !d_CombineDynamicWaves
// Sample in waves for this cascade.
{
#if _FLOW_ON
const half2 flow = Cascade::MakeFlow(slice0).SampleFlow(positionWSXZ);
#if d_Crest_FlowLod
const Flow f = Flow::Make
(
Cascade::MakeFlow(slice0).SampleFlow(positionWSXZ),
g_Crest_Time,
max(3.0 * cascade._Texel, 1.0)
);
float2 offsets, weights;
Flow(cascade._Texel, offsets, weights);
result += cascade.Sample(_Crest_WaveBuffer, positionWSXZ - offsets[0] * flow).xyz * weights[0];
result += cascade.Sample(_Crest_WaveBuffer, positionWSXZ - offsets[1] * flow).xyz * weights[1];
result += cascade.SampleAnimatedWavesOverflow(_Crest_WaveBuffer, positionWSXZ - f._Offset0 * f._Flow, 1.0).xyz * f._Weight0;
result += cascade.SampleAnimatedWavesOverflow(_Crest_WaveBuffer, positionWSXZ - f._Offset1 * f._Flow, 1.0).xyz * f._Weight1;
#else
result += cascade.Sample(_Crest_WaveBuffer, uv).xyz;
#endif // _FLOW_ON
}
// Disabled for last LOD.
#if !_DISABLE_COMBINE
{
const Cascade cascade = Cascade::MakeAnimatedWaves(slice0 + 1);
// Sample the shape 1 texture at this world position.
const float3 uv = cascade.WorldToUV(positionWSXZ);
// Waves to combine down from the next lod up the chain.
SampleDisplacementsCompute(_Crest_Target, cascade._Resolution, uv, 1.0, result);
result += _Crest_WaveBuffer[id].xyz;
#endif
}
#endif
#if _DYNAMIC_WAVE_SIM_ON
// Disabled for last LOD.
#if d_Combine
{
const uint slice1 = slice0 + 1;
const Cascade cascade = Cascade::MakeAnimatedWaves(slice1);
// Sample the shape 1 texture at this world position.
const float3 uv = cascade.WorldToUV(positionWSXZ);
// Waves to combine down from the next lod up the chain.
result += Utility::SampleBilinear(_Crest_Target, uv.xy, slice1, cascade._Resolution);
}
#endif
#if d_DynamicWaves
{
// Convert dynamic wave sim to displacements.
result += Cascade::MakeDynamicWaves(slice0)
.SampleDynamicWavesDisplacement(positionWSXZ, _Crest_HorizontalDisplace, _Crest_DisplaceClamp);
}
#endif // _DYNAMIC_WAVE_SIM_ON
#endif
_Crest_Target[uint3(id.xy, slice0)] = float4(result, 0.0);
_Crest_Target[id] = float4(result, 0.0);
}
void ShapeCombineAnimatedWaves(uint3 id)
{
id.z = _Crest_LodIndex;
ShapeCombine(id);
}
void ShapeCopyAnimatedWaves(uint3 id)
{
ShapeCombine(id);
}
void ShapeCombineDynamicWaves(uint3 id)
{
const uint slice0 = _Crest_LodIndex;
const Cascade cascade = Cascade::MakeAnimatedWaves(slice0);
const float3 uv = cascade.IDToUV(id.xy);
const float2 positionWSXZ = cascade.UVToWorld(uv);
float3 result = 0.0;
// Disabled for last LOD.
#if !_DISABLE_COMBINE
{
// We are sampling from the target which matches Animated Waves descriptor.
const Cascade cascade = Cascade::MakeAnimatedWaves(slice0 + 1);
const float3 uv = cascade.WorldToUV(positionWSXZ);
// Waves to combine down from the next lod up the chain.
SampleDisplacementsCompute(_Crest_DynamicWavesTarget, cascade._Resolution, uv, 1.0, result);
}
#endif
{
// We are sampling from Dynamic Waves.
const Cascade cascade = Cascade::MakeDynamicWaves(slice0);
const float3 uv = cascade.WorldToUV(positionWSXZ);
result += cascade.SampleDynamicWavesDisplacement(uv, _Crest_HorizontalDisplace, _Crest_DisplaceClamp);
}
_Crest_DynamicWavesTarget[uint3(id.xy, slice0)] = float4(result, 0.0);
}
void ShapeCombineCopyDynamicWaves(uint3 id)
{
_Crest_AnimatedWavesTarget[id] += _Crest_DynamicWavesTarget[id];
// We are combining from the target which matches the Animated Waves descriptor.
id.z = _Crest_LodIndex;
ShapeCombine(id);
}
m_CrestNameSpaceEnd
[numthreads(THREAD_GROUP_SIZE_X, THREAD_GROUP_SIZE_Y, 1)] void ShapeCombine(uint3 id : SV_DispatchThreadID) { m_Crest::ShapeCombineBase(id); }
[numthreads(THREAD_GROUP_SIZE_X, THREAD_GROUP_SIZE_Y, 1)] void ShapeCombine_DISABLE_COMBINE(uint3 id : SV_DispatchThreadID) { m_Crest::ShapeCombineBase(id); }
[numthreads(THREAD_GROUP_SIZE_X, THREAD_GROUP_SIZE_Y, 1)] void ShapeCombine_FLOW_ON(uint3 id : SV_DispatchThreadID) { m_Crest::ShapeCombineBase(id); }
[numthreads(THREAD_GROUP_SIZE_X, THREAD_GROUP_SIZE_Y, 1)] void ShapeCombine_FLOW_ON_DISABLE_COMBINE(uint3 id : SV_DispatchThreadID) { m_Crest::ShapeCombineBase(id); }
[numthreads(THREAD_GROUP_SIZE_X, THREAD_GROUP_SIZE_Y, 1)] void ShapeCombine_DYNAMIC_WAVE_SIM_ON(uint3 id : SV_DispatchThreadID) { m_Crest::ShapeCombineBase(id); }
[numthreads(THREAD_GROUP_SIZE_X, THREAD_GROUP_SIZE_Y, 1)] void ShapeCombine_DYNAMIC_WAVE_SIM_ON_DISABLE_COMBINE(uint3 id : SV_DispatchThreadID) { m_Crest::ShapeCombineBase(id); }
[numthreads(THREAD_GROUP_SIZE_X, THREAD_GROUP_SIZE_Y, 1)] void ShapeCombine_FLOW_ON_DYNAMIC_WAVE_SIM_ON(uint3 id : SV_DispatchThreadID) { m_Crest::ShapeCombineBase(id); }
[numthreads(THREAD_GROUP_SIZE_X, THREAD_GROUP_SIZE_Y, 1)] void ShapeCombine_FLOW_ON_DYNAMIC_WAVE_SIM_ON_DISABLE_COMBINE(uint3 id : SV_DispatchThreadID) { m_Crest::ShapeCombineBase(id); }
[numthreads(THREAD_GROUP_SIZE_X, THREAD_GROUP_SIZE_Y, 1)] void ShapeCombineDynamicWaves(uint3 id : SV_DispatchThreadID) { m_Crest::ShapeCombineDynamicWaves(id); }
[numthreads(THREAD_GROUP_SIZE_X, THREAD_GROUP_SIZE_Y, 1)] void ShapeCombineDynamicWaves_DISABLE_COMBINE(uint3 id : SV_DispatchThreadID) { m_Crest::ShapeCombineDynamicWaves(id); }
[numthreads(THREAD_GROUP_SIZE_X, THREAD_GROUP_SIZE_Y, 1)] void ShapeCombineCopyDynamicWaves(uint3 id : SV_DispatchThreadID) { m_Crest::ShapeCombineCopyDynamicWaves(id); }
m_CrestKernelDefault(ShapeCombineAnimatedWaves)
m_CrestKernelDefault(ShapeCopyAnimatedWaves)
m_CrestKernelDefault(ShapeCombineDynamicWaves)

View File

@@ -1,6 +1,8 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
#pragma exclude_renderers glcore gles3
#pragma kernel CrestShorelineColor
#pragma multi_compile_local __ d_Crest_ShorelineColorSource_ShorelineDistance

View File

@@ -3,16 +3,26 @@
// Solves 2D wave equation
#pragma exclude_renderers glcore gles3
#pragma kernel CrestUpdateDynamicWaves
#pragma multi_compile _ CREST_FLOW_ON_INTERNAL
#include "HLSLSupport.cginc"
// Cascade macros expect this to be available.
#define g_Crest_CascadeDynamicWavesSource _Crest_Source
Texture2DArray _Crest_Source;
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Keywords.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Macros.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Constants.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Globals.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/InputsDriven.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Cascade.hlsl"
RWTexture2DArray<float2> _Crest_Target;
RWTexture2DArray<m_Float2> _Crest_Target;
CBUFFER_START(CrestPerMaterial)
float _Crest_Damping;
@@ -37,15 +47,15 @@ float ComputeWaveSpeed(float wavelength, float g)
void UpdateDynamicWaves(uint3 id)
{
// Slice to sample previous frames data from. LOD change takes into account shifting of the cascades in scale.
const float sliceIndexSource = id.z + _Crest_LodChange;
const uint sliceIndexSource = id.z + _Crest_LodChange;
const Cascade cascadeSource = Cascade::MakeDynamicWavesSource(sliceIndexSource);
// Off either end of the cascade. Not useful to sample anything from previous
// frame, as we do not produce any new data from sources of waves.
if (sliceIndexSource < 0.0 || sliceIndexSource >= cascadeSource._Count)
if (sliceIndexSource < 0 || sliceIndexSource >= g_Crest_LodCount)
{
// Always initialise with 0 values.
_Crest_Target[id] = (float2)0;
_Crest_Target[id] = 0.0;
return;
}
@@ -72,12 +82,17 @@ void UpdateDynamicWaves(uint3 id)
// Wave reflections off geometry.
if (waterDepth <= 0.0)
{
_Crest_Target[id] = float2(0.0, 0.0);
_Crest_Target[id] = 0.0;
return;
}
float2 worldPosXZFlowed = worldPosXZ;
#if d_Crest_FlowLod
const half2 velocity = Cascade::MakeFlow(sliceIndex).SampleFlow(worldPosXZ);
const float2 worldPosXZFlowed = worldPosXZ - dt * velocity;
worldPosXZFlowed -= velocity * dt;
#endif
const float3 uv_source = cascadeSource.WorldToUV(worldPosXZFlowed);
// weighting for source position - weight 0 for off texture accesses to stop streaky artifacts
@@ -142,7 +157,7 @@ void UpdateDynamicWaves(uint3 id)
vtp = 0.0;
}
_Crest_Target[id] = float2(ftp, vtp);
_Crest_Target[id] = m_Float2Constructor(ftp, vtp);
}
m_CrestNameSpaceEnd

View File

@@ -1,14 +1,24 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
#pragma exclude_renderers glcore gles3
#pragma kernel CrestUpdateFoam
#pragma multi_compile _ CREST_FLOW_ON_INTERNAL
// Cascade macros expect this to be available.
#define g_Crest_CascadeFoamSource _Crest_Source
Texture2DArray _Crest_Source;
#include "HLSLSupport.cginc"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Keywords.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Macros.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Constants.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Globals.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/InputsDriven.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Helpers.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Cascade.hlsl"
RWTexture2DArray<float> _Crest_Target;
@@ -21,7 +31,6 @@ float _Crest_WaveFoamCoverage;
float _Crest_ShorelineFoamMaxDepth;
float _Crest_ShorelineFoamStrength;
float _Crest_SimDeltaTime;
float _Crest_SimDeltaTimePrev;
float _Crest_LodChange;
bool _Crest_NeedsPrewarming;
uint _Crest_MinimumWavesSlice;
@@ -39,10 +48,14 @@ void UpdateFoam(uint3 id)
// Sample from previous frame.
{
float2 positionXZ = worldPosXZ;
#if d_Crest_FlowLod
const half2 velocity = Cascade::MakeFlow(slice0).SampleFlow(worldPosXZ);
const float2 positionXZ = worldPosXZ - _Crest_SimDeltaTime * velocity;
positionXZ -= velocity * _Crest_SimDeltaTime;
#endif
// Slice to sample previous frames data from. LOD change takes into account shifting of the cascades in scale.
const float sliceIndexSource = clamp(id.z + _Crest_LodChange, 0.0, cascade._Count - 1.0);
const uint sliceIndexSource = ComputeSlice(slice0, _Crest_LodChange, g_Crest_LodCount - 1);
foam = Cascade::MakeFoamSource(sliceIndexSource).SampleFoamOverflow(positionXZ, 1.0);
}
@@ -53,9 +66,16 @@ void UpdateFoam(uint3 id)
// accumulation of foam and causes overshoots when _Crest_WaveFoamStrength is less than 1.0.
float simDeltaTime = _Crest_NeedsPrewarming ? max(_Crest_SimDeltaTime, min(1.0, _Crest_WaveFoamStrength - 1.0) / _Crest_FoamFadeRate) : _Crest_SimDeltaTime;
// Limit wave contributions at low water scales only where filtering is needed.
uint filteredSlice = slice0;
if (g_Crest_WaterScale <= 8)
{
filteredSlice = max(_Crest_MinimumWavesSlice, filteredSlice);
}
// The determinant of the displacement Jacobian is a good measure for turbulence.
float det;
const half3 displacement = Cascade::MakeAnimatedWaves(max(_Crest_MinimumWavesSlice, slice0)).SampleDisplacement(worldPosXZ, det);
const half3 displacement = Cascade::MakeAnimatedWaves(filteredSlice).SampleDisplacement(worldPosXZ, det);
foam += 5.0 * simDeltaTime * _Crest_WaveFoamStrength * saturate( _Crest_WaveFoamCoverage - det );
// Prewarm shoreline foam. 1.0 / _Crest_FoamFadeRate perfectly matches a paused water in edit mode which is fine for

View File

@@ -3,6 +3,8 @@
// Soft shadow term is red, hard shadow term is green.
#pragma exclude_renderers glcore gles3
#pragma kernel CrestUpdateShadowsBRP _BRP
#pragma kernel CrestUpdateShadowsHRP _HRP
#pragma kernel CrestUpdateShadowsURP _URP
@@ -11,13 +13,19 @@
#pragma multi_compile __ SHADOWS_SPLIT_SPHERES
#pragma multi_compile __ SHADOWS_SINGLE_CASCADE
// Cascade macros expect this to be available.
#define g_Crest_CascadeShadowSource _Crest_Source
Texture2DArray _Crest_Source;
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Utility/RP/Compute.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Utility/RP/Shadows.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Keywords.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Macros.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Constants.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Globals.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/InputsDriven.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Helpers.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Cascade.hlsl"
// Noise functions used for jitter.
@@ -33,7 +41,7 @@ bool _Crest_SampleColorMap;
float3 _Crest_Absorption;
float3 _Crest_Scattering;
RWTexture2DArray<float2> _Crest_Target;
RWTexture2DArray<m_Float2> _Crest_Target;
m_CrestNameSpace
@@ -79,7 +87,7 @@ void UpdateShadows(const uint3 id)
positionWS.y = g_Crest_WaterCenter.y;
// Shadow from last frame. Manually implement black border.
const float sliceIndexSource = clamp((int)slice0 + g_Crest_LodChange, 0.0, g_Crest_LodCount - 1.0);
const uint sliceIndexSource = ComputeSlice(slice0, g_Crest_LodChange, g_Crest_LodCount - 1);
half2 shadow = Cascade::MakeShadowSource(sliceIndexSource).SampleShadowOverflow(positionWS.xz, 1.0);
// Add displacement so shorelines do not receive shadows incorrectly.
@@ -108,15 +116,19 @@ void UpdateShadows(const uint3 id)
half3 absorption = _Crest_Absorption;
half3 scattering = _Crest_Scattering;
#if d_Crest_AbsorptionLod
if (g_Crest_SampleAbsorptionSimulation)
{
absorption = Cascade::MakeAbsorption(slice0).SampleAbsorption(positionWS.xz);
}
#endif
#if d_Crest_ScatteringLod
if (g_Crest_SampleScatteringSimulation)
{
scattering = Cascade::MakeScattering(slice0).SampleScattering(positionWS.xz);
}
#endif
half3 extinction = absorption + scattering;
half factor = saturate(min(min(extinction.x, extinction.y), extinction.z) * g_Crest_DynamicSoftShadowsFactor);
@@ -146,7 +158,7 @@ void UpdateShadows(const uint3 id)
shadow = lerp(shadow, shadowThisFrame, _Crest_JitterDiameters_CurrentFrameWeights.zw * _Crest_SimDeltaTime * 60.0);
}
_Crest_Target[id] = shadow;
_Crest_Target[id] = m_Float2FromFloat2(shadow);
}
m_CrestNameSpaceEnd

View File

@@ -1,176 +1,4 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
// Soft shadow term is red, hard shadow term is green. In HDRP, hard shadows are not computed and y channel will be 0.
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Macros.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Constants.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Globals.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/InputsDriven.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Cascade.hlsl"
// Noise functions used for jitter.
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Utility/Noise/Noise.hlsl"
CBUFFER_START(CrestPerMaterial)
// Settings._jitterDiameterSoft, Settings._jitterDiameterHard, Settings._currentFrameWeightSoft, Settings._currentFrameWeightHard
float4 _Crest_JitterDiameters_CurrentFrameWeights;
float _Crest_SimDeltaTime;
bool _Crest_ClearShadows;
float3 _Crest_CenterPos;
float3 _Crest_Scale;
float4x4 _Crest_MainCameraProjectionMatrix;
bool _Crest_SampleColorMap;
float3 _Crest_Absorption;
float3 _Crest_Scattering;
CBUFFER_END
m_CrestNameSpace
struct Attributes
{
uint id : SV_VertexID;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float3 positionWS : TEXCOORD0;
UNITY_VERTEX_OUTPUT_STEREO
};
Varyings Vertex(Attributes input)
{
// This will work for all pipelines.
Varyings output = (Varyings)0;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
output.positionCS = GetFullScreenTriangleVertexPosition(input.id);
float2 uv = GetFullScreenTriangleTexCoord(input.id);
// World position from UV.
output.positionWS.xyz = float3(uv.x - 0.5, 0.0, uv.y - 0.5) * _Crest_Scale * 4.0 + _Crest_CenterPos;
output.positionWS.y = g_Crest_WaterCenter.y;
return output;
}
half SampleShadows(const float4 i_positionWS);
half ComputeShadowFade(const float4 i_positionWS);
// Compiler shows warning when using intermediate returns, disable this.
#pragma warning(push)
#pragma warning(disable: 4000)
half ComputeShadow(const float4 i_positionWS, const float i_jitterDiameter, const half i_terrainHeight)
{
float4 positionWS = i_positionWS;
if (i_jitterDiameter > 0.0)
{
// Add jitter.
positionWS.xz += i_jitterDiameter * (hash33(uint3(abs(positionWS.xz * 10.0), _Time.y * 120.0)) - 0.5).xy;
// Shadow Bleeding.
// If we are not within a terrain, then check for shadow bleeding.
if (i_positionWS.y > i_terrainHeight)
{
// WorldToSafeUV
half terrainHeight = Cascade::MakeDepth(_Crest_LodIndex).SampleSceneHeight(positionWS.xz);
// If our current position is below the jittered terrain height, then we have landed within a terrain and
// we do not want to sample those shadows.
if (i_positionWS.y < terrainHeight)
{
// Return no shadows.
return 1.0;
}
}
}
return SampleShadows(positionWS);
}
#pragma warning(pop)
half2 Fragment(Varyings input)
{
float4 positionWS = float4(input.positionWS.xyz, 1.0);
// Shadow from last frame. Manually implement black border.
const float sliceIndexSource = clamp((int)_Crest_LodIndex + g_Crest_LodChange, 0.0, g_Crest_LodCount - 1.0);
half2 shadow = Cascade::MakeShadowSource(sliceIndexSource).SampleShadowOverflow(positionWS.xz, 1.0);
// Add displacement so shorelines do not receive shadows incorrectly.
positionWS.xyz += Cascade::MakeAnimatedWaves(_Crest_LodIndex).SampleDisplacement(positionWS.xz);
// This was calculated in vertex but we have to sample sea level offset in fragment.
float4 mainCameraCoordinates = mul(_Crest_MainCameraProjectionMatrix, positionWS);
// Check if the current sample is visible in the main camera (and therefore the shadow map can be sampled). This is
// required as the shadow buffer is world aligned and surrounds viewer.
float3 projected = mainCameraCoordinates.xyz / mainCameraCoordinates.w;
if (projected.z < 1.0 && projected.z > 0.0 && abs(projected.x) < 1.0 && abs(projected.y) < 1.0)
{
half2 shadowThisFrame = 1.0;
#if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0)
positionWS.xyz -= _WorldSpaceCameraPos.xyz;
#endif
half terrainHeight = Cascade::MakeDepth(_Crest_LodIndex).SampleSceneHeight(positionWS.xz);
half softJitter = _Crest_JitterDiameters_CurrentFrameWeights[CREST_SHADOW_INDEX_SOFT];
if (_Crest_SampleColorMap)
{
half3 absorption = _Crest_Absorption;
half3 scattering = _Crest_Scattering;
if (g_Crest_SampleAbsorptionSimulation)
{
absorption = Cascade::MakeAbsorption(_Crest_LodIndex).SampleAbsorption(positionWS.xz);
}
if (g_Crest_SampleScatteringSimulation)
{
scattering = Cascade::MakeScattering(_Crest_LodIndex).SampleScattering(positionWS.xz);
}
half3 extinction = absorption + scattering;
half factor = saturate(min(min(extinction.x, extinction.y), extinction.z) * g_Crest_DynamicSoftShadowsFactor);
softJitter = (1.0 - factor) * k_Crest_MaximumShadowJitter;
}
// Add soft shadowing data.
shadowThisFrame[CREST_SHADOW_INDEX_SOFT] = ComputeShadow
(
positionWS,
softJitter,
terrainHeight
);
#ifdef CREST_SAMPLE_SHADOW_HARD
// Add hard shadowing data.
shadowThisFrame[CREST_SHADOW_INDEX_HARD] = ComputeShadow
(
positionWS,
_Crest_JitterDiameters_CurrentFrameWeights[CREST_SHADOW_INDEX_HARD],
terrainHeight
);
#endif
shadowThisFrame = (half2)1.0 - saturate(shadowThisFrame + ComputeShadowFade(positionWS));
shadow = lerp(shadow, shadowThisFrame, _Crest_JitterDiameters_CurrentFrameWeights.zw * _Crest_SimDeltaTime * 60.0);
}
return shadow;
}
m_CrestNameSpaceEnd
m_CrestVertex
m_CrestFragment(half2)
// Replaced with UpdateShadow.compute.

View File

@@ -39,6 +39,7 @@
result._Texture = g_Crest_Cascade##name##source; \
result._SamplingParameters = g_Crest_SamplingParametersCascade##name##source; \
result._Index = i_Index; \
result._IndexI = i_Index; \
result._PositionSnapped = perSlice.xy; \
result._Texel = perSlice.z; \
result._Resolution = perType.y; \
@@ -56,6 +57,7 @@
result._Texture = i_Cascade._Texture; \
result._SamplingParameters = i_Cascade._SamplingParameters; \
result._Index = i_Index; \
result._IndexI = i_Index; \
result._PositionSnapped = perSlice.xy; \
result._Texel = perSlice.z; \
result._Resolution = perType.y; \
@@ -70,6 +72,7 @@
const float4 perAll = g_Crest_CascadeData##source[i_Index]; \
Cascade result; \
result._Index = i_Index; \
result._IndexI = i_Index; \
result._Scale = perAll.x; \
result._Weight = perAll.y; \
result._MaximumWavelength = perAll.z; \
@@ -140,6 +143,51 @@
} \
} \
return result; \
} \
half4 Sample##name##Overflow(const Texture2DArray i_Texture, const float2 i_Position, const float i_Border) m_ConstantReturn \
{ \
half4 result = 0.0; \
const float3 uv = WorldToUV(i_Position); \
const half2 r = abs(uv.xy - 0.5); \
const half rMax = 0.5 - _OneOverResolution * i_Border; \
if (max(r.x, r.y) <= rMax) \
{ \
result = Sample(i_Texture, uv); \
} \
else if ((_Index + 1) < _Count) \
{ \
const Cascade cascade = Cascade::Make##name(_Index + 1, this); \
const float3 uv = cascade.WorldToUV(i_Position); \
const half2 r = abs(uv.xy - 0.5); \
const half rMax = 0.5 - cascade._OneOverResolution * i_Border; \
if (max(r.x, r.y) <= rMax) \
{ \
result = Sample(i_Texture, uv); \
} \
} \
return result; \
} \
half4 Sample##name##Overflow(const Texture2DArray i_Texture, const float3 i_UV, const float i_Border) m_ConstantReturn \
{ \
half4 result = 0.0; \
const half2 r = abs(i_UV.xy - 0.5); \
const half rMax = 0.5 - _OneOverResolution * i_Border; \
if (max(r.x, r.y) <= rMax) \
{ \
result = Sample(i_Texture, i_UV); \
} \
else if ((_Index + 1) < _Count) \
{ \
const Cascade cascade = Cascade::Make##name(_Index + 1, this); \
const float3 uv = cascade.WorldToUV(UVToWorld(i_UV)); \
const half2 r = abs(uv.xy - 0.5); \
const half rMax = 0.5 - cascade._OneOverResolution * i_Border; \
if (max(r.x, r.y) <= rMax) \
{ \
result = Sample(i_Texture, uv); \
} \
} \
return result; \
}
#define m_SampleWeighted(name, type) \
@@ -167,6 +215,7 @@ struct Cascade
float _Count;
float _OneOverResolution;
float _Texel;
// NOTE: Currently set to Dynamic Waves, as it is only used by SphereWaterInteraction.compute.
float _MaximumWavelength;
float _Scale;
@@ -175,6 +224,8 @@ struct Cascade
// For copy constructor.
float4 _SamplingParameters[MAX_LOD_COUNT];
uint _IndexI;
m_MakeCascadeShared
m_MakeCascadeSharedPrevious
@@ -183,6 +234,7 @@ struct Cascade
const float4 perAll = i_Previous ? g_Crest_CascadeDataSource[i_Index] : g_Crest_CascadeData[i_Index];
Cascade result;
result._Index = i_Index;
result._IndexI = i_Index;
result._Scale = perAll.x;
result._Weight = perAll.y;
result._MaximumWavelength = perAll.z;
@@ -202,19 +254,25 @@ struct Cascade
m_MakeCascadeCopy(Depth)
m_MakeCascade(DynamicWaves)
m_MakeCascadeCopy(DynamicWaves)
#ifdef g_Crest_CascadeDynamicWavesSource
m_MakeCascadePrevious(DynamicWaves)
#endif
m_MakeCascade(Flow)
m_MakeCascadeCopy(Flow)
m_MakeCascade(Foam)
m_MakeCascadeCopy(Foam)
#ifdef g_Crest_CascadeFoamSource
m_MakeCascadePrevious(Foam)
#endif
m_MakeCascade(Level)
m_MakeCascadeCopy(Level)
m_MakeCascade(Scattering)
m_MakeCascadeCopy(Scattering)
m_MakeCascade(Shadow)
m_MakeCascadeCopy(Shadow)
#ifdef g_Crest_CascadeShadowSource
m_MakeCascadePrevious(Shadow)
#endif
// Convert compute shader id to uv texture coordinates
float3 IDToUV(const uint2 i_ID) m_ConstantReturn
@@ -232,6 +290,12 @@ struct Cascade
return float3((i_Position - _PositionSnapped) / (_Texel * _Resolution) + 0.5, _Index);
}
uint3 WorldToID(const float2 i_Position) m_ConstantReturn
{
const float3 uv = WorldToUV(i_Position);
return uint3(uv.xy * _Resolution, _IndexI);
}
float2 IDToWorld(const uint2 i_ID) m_ConstantReturn
{
return UVToWorld(IDToUV(i_ID));
@@ -305,6 +369,7 @@ struct Cascade
m_Sample(Depth, half2, .xy)
m_SampleWeighted(Depth, half2)
m_Sample(DynamicWaves, half2, .xy)
m_SampleWeighted(DynamicWaves, half2)
m_Sample(Flow, half2, .xy)
m_SampleWeighted(Flow, half2)
m_Sample(Foam, half, .x)
@@ -354,18 +419,15 @@ struct Cascade
float4 position = SampleAnimatedWaves(uv);
io_LevelOffset += position.w * i_Weight;
io_Position += position.xyz * i_Weight;
io_Position.y += position.w * i_Weight;
// Derivatives
{
// Compute derivative of water level - needed to get base normal of water. Water
// normal, normal map etc is then added to base normal.
const float2 dd = float2(_OneOverResolution, 0.0);
const float xOffset = SampleAnimatedWaves(uv + dd.xyy).w;
const float zOffset = SampleAnimatedWaves(uv + dd.yxy).w;
// TODO: Is weight in correct position?
io_Derivatives.x += i_Weight * (xOffset - position.w) / _Texel;
io_Derivatives.y += i_Weight * (zOffset - position.w) / _Texel;
const float2 offset = float2(SampleAnimatedWaves(uv + dd.xyy).w, SampleAnimatedWaves(uv + dd.yxy).w);
io_Derivatives += ((offset - position.w) / _Texel) * i_Weight;
}
}
@@ -405,8 +467,7 @@ struct Cascade
return normalize(xProduct).xz;
}
// TODO: Rename
void SampleNormals(const float2 i_Position, const float i_Weight, inout half2 io_Normal, inout half io_Determinant) m_ConstantReturn
void SampleDisplacementNormal(const float2 i_Position, const float i_Weight, inout half2 io_Normal, inout half io_Determinant) m_ConstantReturn
{
float3 xDisplacement; float3 zDisplacement;
half3 displacement = __SampleDisplacements(i_Position, xDisplacement, zDisplacement).xyz;
@@ -456,6 +517,13 @@ struct Cascade
return value;
}
void SampleSignedDepthFromSeaLevelAndDistance(const float2 i_Position, const float i_Weight, inout half io_Depth, inout half io_Distance) m_ConstantReturn
{
const half2 value = SampleSignedDepthFromSeaLevelAndDistance(i_Position) * i_Weight;
io_Depth += value.x;
io_Distance += value.y;
}
void SampleSignedDepthFromSeaLevel(const float2 i_Position, const float i_Weight, inout half io_Depth) m_ConstantReturn
{
io_Depth += (g_Crest_WaterCenter.y - SampleSceneHeight(i_Position)) * i_Weight;

View File

@@ -26,6 +26,8 @@
// C# code to check if any parameters are within the MAX_LOD_COUNT limits
#define MAX_LOD_COUNT 15
#define k_Crest_WaveOctaveCount 14
// How light is attenuated deep in water
#define DEPTH_OUTSCATTER_CONSTANT 0.25
@@ -42,6 +44,9 @@
#define CREST_SSS_MAXIMUM 0.6
#define CREST_SSS_RANGE 0.12
// Rudimentary SSS approximation for additional lights.
#define k_Crest_AdditionalLightLerp 0.25
// Note: Must match k_MaskBelowSurface in UnderwaterRenderer.Mask.cs.
// Fog rendered from below.
#define CREST_MASK_BELOW_SURFACE -1.0

View File

@@ -41,6 +41,22 @@ struct Flow
flow._Flow = i_Flow;
return flow;
}
static Flow Make
(
const half2 i_Flow,
const float4 i_FlowParameters
)
{
Flow flow;
flow._Offset0 = i_FlowParameters.x;
flow._Weight0 = i_FlowParameters.y;
flow._Offset1 = i_FlowParameters.z;
flow._Weight1 = i_FlowParameters.w;
flow._Period = 1.0;
flow._Flow = i_Flow;
return flow;
}
};
m_CrestNameSpaceEnd

View File

@@ -8,23 +8,32 @@
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Settings.Crest.hlsl"
// Try and use already defined samplers.
// Packages/com.unity.shadergraph/ShaderGraphLibrary/ShaderVariables.hlsl
// Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl
#if defined(SHADERCONFIG_CS_HLSL) && defined(UNITY_SHADER_VARIABLES_INCLUDED)
#define LODData_linear_clamp_sampler s_linear_clamp_sampler
#else
SamplerState LODData_linear_clamp_sampler;
SamplerState LODData_point_clamp_sampler;
SamplerState sampler_Crest_linear_repeat;
SamplerState _Crest_linear_clamp_sampler;
#endif
CBUFFER_START(CrestPerFrame)
float3 g_Crest_WaterCenter;
float g_Crest_WaterScale;
float g_Crest_Time;
float g_Crest_LodCount;
uint g_Crest_LodCount;
int g_Crest_LodChange;
float g_Crest_MeshScaleLerp;
float g_Crest_ClipByDefault;
float g_Crest_LodAlphaBlackPointFade;
float g_Crest_LodAlphaBlackPointWhitePointFade;
float4 g_Crest_Flow;
// Refraction
float g_Crest_WaterDepthAtViewer;
float g_Crest_MaximumVerticalDisplacement;
float2 g_Crest_HorizonNormal;
// Hack - due to SV_IsFrontFace occasionally coming through as true for
// backfaces, add a param here that forces water to be in undrwater state. I
// think the root cause here might be imprecision or numerical issues at water
@@ -34,6 +43,7 @@ int g_Crest_ForceUnderwater;
float3 g_Crest_PrimaryLightDirection;
float3 g_Crest_PrimaryLightIntensity;
bool g_Crest_PrimaryLightHasCookie;
bool g_Crest_PrimaryLightFallback;
float g_Crest_DynamicSoftShadowsFactor;

View File

@@ -36,6 +36,29 @@ m_Blend(float2)
m_Blend(float3)
m_Blend(float4)
// Enforces casting hygiene.
uint ComputeSlice(uint slice, int offset, uint maximum)
{
// We cast to int since offset can be negative.
// We must cast all parameters otherwise problems occur.
return clamp((int)slice + offset, 0, (int)maximum);
}
float PositionToSliceNumber
(
const float2 i_PositionXZ,
const float i_MinimumSlice,
const float i_MaximumSlice,
const float i_WaterScale0
)
{
const float2 offset = abs(i_PositionXZ - g_Crest_WaterCenter.xz);
const float taxicab = max(offset.x, offset.y);
const float radius0 = i_WaterScale0;
const float slice = log2(max(taxicab / radius0, 1.0));
return clamp(slice, i_MinimumSlice, i_MaximumSlice);
}
uint PositionToSliceIndex
(
const float2 i_PositionXZ,
@@ -43,50 +66,106 @@ uint PositionToSliceIndex
const float i_WaterScale0
)
{
const float2 offsetFromCenter = abs(i_PositionXZ - g_Crest_WaterCenter.xz);
const float taxicab = max(offsetFromCenter.x, offsetFromCenter.y);
const float radius0 = i_WaterScale0;
float sliceNumber = log2(max(taxicab / radius0, 1.0));
// Don't use last slice - this is a "transition" slice used to cross fade waves
// between LOD resolutions to avoid pops.
sliceNumber = clamp(sliceNumber, i_MinimumSlice, g_Crest_LodCount - 2.0);
return floor(sliceNumber);
const float slice = PositionToSliceNumber
(
i_PositionXZ,
i_MinimumSlice,
g_Crest_LodCount - 2,
i_WaterScale0
);
return floor(slice);
}
void PosToSliceIndices
void PositionToSliceIndices
(
const float2 worldXZ,
const float minSlice,
const float maxSlice,
const float waterScale0,
out uint slice0,
out uint slice1,
out float lodAlpha
const float2 i_PositionXZ,
const uint i_MinimumSlice,
const uint i_MaximumSlice,
const float i_WaterScale0,
out uint o_Slice0,
out uint o_Slice1,
out float o_LodAlpha
)
{
const float2 offsetFromCenter = abs(worldXZ - g_Crest_WaterCenter.xz);
const float taxicab = max(offsetFromCenter.x, offsetFromCenter.y);
const float radius0 = waterScale0;
float sliceNumber = log2( max( taxicab / radius0, 1.0 ) );
sliceNumber = clamp( sliceNumber, minSlice, maxSlice );
const float slice = PositionToSliceNumber
(
i_PositionXZ,
i_MinimumSlice,
i_MaximumSlice,
i_WaterScale0
);
lodAlpha = frac(sliceNumber);
o_LodAlpha = frac(slice);
// Fixes artefact with DX12 & Vulkan. Likely a compiler bug.
// Sampling result appears to be all over the place.
slice0 = floor(sliceNumber) + 0.01;
slice1 = slice0 + 1;
o_Slice0 = floor(slice) + 0.01;
o_Slice1 = o_Slice0 + 1;
// lod alpha is remapped to ensure patches weld together properly. patches can vary significantly in shape (with
// strips added and removed), and this variance depends on the base density of the mesh, as this defines the strip width.
// using .15 as black and .85 as white should work for base mesh density as low as 16.
const float BLACK_POINT = 0.15, WHITE_POINT = 0.85;
lodAlpha = saturate((lodAlpha - BLACK_POINT) / (WHITE_POINT - BLACK_POINT));
o_LodAlpha = saturate((o_LodAlpha - BLACK_POINT) / (WHITE_POINT - BLACK_POINT));
if (slice0 == 0)
if (o_Slice0 == 0)
{
// blend out lod0 when viewpoint gains altitude. we're using the global g_Crest_MeshScaleLerp so check for LOD0 is necessary
lodAlpha = min(lodAlpha + g_Crest_MeshScaleLerp, 1.0);
o_LodAlpha = min(o_LodAlpha + g_Crest_MeshScaleLerp, 1.0);
}
}
// Use this when rendering a quad as the surface.
void MeshPositionToSliceIndices
(
const float2 i_PositionXZ,
const float i_MinimumSlice,
const float i_MaximumSlice,
const float i_WaterScale0,
out uint o_Slice0,
out uint o_Slice1,
out float o_LodAlpha
)
{
float slice = PositionToSliceNumber
(
i_PositionXZ,
i_MinimumSlice,
i_MaximumSlice + 1,
i_WaterScale0
);
o_LodAlpha = frac(slice);
uint extent = floor(slice);
slice = min(slice, i_MaximumSlice);
// Fixes artefact with DX12 & Vulkan. Likely a compiler bug.
// Sampling result appears to be all over the place.
o_Slice0 = floor(slice) + 0.01;
o_Slice1 = o_Slice0 + 1;
// lod alpha is remapped to ensure patches weld together properly. patches can vary significantly in shape (with
// strips added and removed), and this variance depends on the base density of the mesh, as this defines the strip width.
// using .15 as black and .85 as white should work for base mesh density as low as 16.
const float BLACK_POINT = 0.15, WHITE_POINT = 0.85;
o_LodAlpha = saturate((o_LodAlpha - BLACK_POINT) / (WHITE_POINT - BLACK_POINT));
if (o_Slice0 == 0)
{
// blend out lod0 when viewpoint gains altitude. we're using the global g_Crest_MeshScaleLerp so check for LOD0 is necessary
o_LodAlpha = min(o_LodAlpha + g_Crest_MeshScaleLerp, 1.0);
}
// Matches mesh solution.
// Comparing to maxSlice + 1 can make any maxSlice work, but no point.
if (extent == g_Crest_LodCount)
{
o_LodAlpha = 1.0;
}
}
@@ -115,11 +194,21 @@ bool IsUnderWater(const bool i_FrontFace, const int i_ForceUnderwater)
float FeatherWeightFromUV(const float2 i_uv, const half i_featherWidth)
{
float2 offset = abs(i_uv - 0.5);
float r_l1 = max(offset.x, offset.y) - (0.5 - i_featherWidth);
if (i_featherWidth > 0.0) r_l1 /= i_featherWidth;
float weight = saturate(1.0 - r_l1);
return weight;
const float2 offset = abs(i_uv - 0.5);
const float largest = max(offset.x, offset.y);
// Early exit (also handles zero feather).
if (largest > 0.5)
{
return 0.0;
}
else
{
float r_l1 = max(offset.x, offset.y) - (0.5 - i_featherWidth);
if (i_featherWidth > 0.0) r_l1 /= i_featherWidth;
float weight = saturate(1.0 - r_l1);
return weight;
}
}
bool WithinUV(const float2 i_UV)

View File

@@ -21,13 +21,10 @@ Texture2DArray g_Crest_CascadeDepth;
m_DisplacementTexture(Texture2DArray, 4) g_Crest_CascadeLevel;
Texture2DArray g_Crest_CascadeClip;
Texture2DArray g_Crest_CascadeFoam;
Texture2DArray g_Crest_CascadeFoamSource;
Texture2DArray g_Crest_CascadeFlow;
Texture2DArray g_Crest_CascadeDynamicWaves;
Texture2DArray g_Crest_CascadeDynamicWavesSource;
Texture2DArray g_Crest_CascadeScattering;
Texture2DArray g_Crest_CascadeShadow;
Texture2DArray g_Crest_CascadeShadowSource;
Texture2DArray g_Crest_CascadeAlbedo;

View File

@@ -0,0 +1,17 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
#ifndef d_WaveHarmonic_Crest_Keywords
#define d_WaveHarmonic_Crest_Keywords
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Settings.Crest.hlsl"
#define d_Crest_AlbedoLod CREST_ALBEDO_SIMULATION
#define d_Crest_FlowLod defined(_CREST_FLOW_LOD) || defined(CREST_FLOW_ON_INTERNAL)
#define d_Crest_ShadowLod CREST_SHADOW_SIMULATION
#define d_Crest_AbsorptionLod CREST_ABSORPTION_SIMULATION
#define d_Crest_ScatteringLod CREST_SCATTERING_SIMULATION
#define d_Crest_OutScattering CREST_OUT_SCATTERING
#endif

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 2e2c3338345cc4cc79fac0ec9b65a4f2
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -13,6 +13,22 @@
#define m_FloatMaximum 3.402823466e+38
//
// Fallback for WebGPU
//
#ifdef SHADER_API_WEBGPU
#define m_Float2 float4
#define m_Float2Constructor(x, y) float4(x, y, 0.0, 0.0)
#define m_Float2FromFloat2(p0) float4(p0.x, p0.y, 0, 0)
#else
#define m_Float2 float2
#define m_Float2Constructor(x, y) float2(x, y)
#define m_Float2FromFloat2(p0) p0
#endif
#if (CREST_FULL_PRECISION_DISPLACEMENT != 0)
#define m_DisplacementTexture(texture, components) texture<float##components>
#else

View File

@@ -1,19 +1,27 @@
//
// This file was automatically generated. Please don't edit by hand. Execute Editor command [ Edit > Rendering > Generate Shader Includes ] instead
//
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
#ifndef SETTINGS_CREST_HLSL
#define SETTINGS_CREST_HLSL
//
// WaveHarmonic.Crest.Editor.ShaderSettings: static fields
//
#define CREST_PACKAGE_HDRP (1)
#define CREST_PACKAGE_URP (1)
#define CREST_PORTALS (0)
#define CREST_SHIFTING_ORIGIN (0)
#define CREST_FULL_PRECISION_DISPLACEMENT (1)
#define CREST_DISCARD_ATMOSPHERIC_SCATTERING (1)
#define CREST_LEGACY_UNDERWATER (0)
#ifndef d_WaveHarmonic_Crest_Settings
#define d_WaveHarmonic_Crest_Settings
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Settings/Settings.Crest.hlsl"
#if CREST_PLATFORM_STANDALONE
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Settings/Settings.Crest.Standalone.hlsl"
#elif CREST_PLATFORM_SERVER
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Settings/Settings.Crest.Server.hlsl"
#elif CREST_PLATFORM_ANDROID
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Settings/Settings.Crest.Android.hlsl"
#elif CREST_PLATFORM_IOS
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Settings/Settings.Crest.iOS.hlsl"
#elif CREST_PLATFORM_WEB
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Settings/Settings.Crest.Web.hlsl"
#elif CREST_PLATFORM_TVOS
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Settings/Settings.Crest.tvOS.hlsl"
#elif CREST_PLATFORM_VISIONOS
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Settings/Settings.Crest.visionOS.hlsl"
#else
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Settings/Settings.Crest.Default.hlsl"
#endif
#endif // d_WaveHarmonic_Crest_Settings

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bb30ad2b71bed4acca040c6ce2900f37
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,26 @@
//
// This file was automatically generated. Please don't edit by hand. Execute Editor command [ Edit > Rendering > Generate Shader Includes ] instead
//
#ifndef SETTINGS_CREST_ANDROID_HLSL
#define SETTINGS_CREST_ANDROID_HLSL
//
// WaveHarmonic.Crest.Editor.ShaderSettingsAndroid: static fields
//
#define CREST_ALBEDO_SIMULATION (1)
#define CREST_ABSORPTION_SIMULATION (1)
#define CREST_SCATTERING_SIMULATION (1)
#define CREST_SHADOW_SIMULATION (1)
#define CREST_OUT_SCATTERING (1)
#define CREST_NORMAL_MAPS (1)
#define CREST_PLANAR_REFLECTIONS (1)
#define CREST_PLANAR_REFLECTIONS_APPLY_SMOOTHNESS (1)
#define CREST_FOAM_SAMPLING_MULTI_SCALE (1)
#define CREST_FOAM_SAMPLING_STOCHASTIC (0)
#define CREST_FOAM_BIOLUMINESCENCE (1)
#define CREST_CAUSTICS_FORCE_DISTORTION (1)
#define CREST_ADDITIONAL_LIGHTS (1)
#define CREST_SIMPLE_TRANSPARENCY (0)
#endif

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 307613c3b5e1c4f7da556862bfea5712
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,26 @@
//
// This file was automatically generated. Please don't edit by hand. Execute Editor command [ Edit > Rendering > Generate Shader Includes ] instead
//
#ifndef SETTINGS_CREST_DEFAULT_HLSL
#define SETTINGS_CREST_DEFAULT_HLSL
//
// WaveHarmonic.Crest.Editor.ShaderSettingsDefault: static fields
//
#define CREST_ALBEDO_SIMULATION (1)
#define CREST_ABSORPTION_SIMULATION (1)
#define CREST_SCATTERING_SIMULATION (1)
#define CREST_SHADOW_SIMULATION (1)
#define CREST_OUT_SCATTERING (1)
#define CREST_NORMAL_MAPS (1)
#define CREST_PLANAR_REFLECTIONS (1)
#define CREST_PLANAR_REFLECTIONS_APPLY_SMOOTHNESS (1)
#define CREST_FOAM_SAMPLING_MULTI_SCALE (1)
#define CREST_FOAM_SAMPLING_STOCHASTIC (0)
#define CREST_FOAM_BIOLUMINESCENCE (1)
#define CREST_CAUSTICS_FORCE_DISTORTION (1)
#define CREST_ADDITIONAL_LIGHTS (1)
#define CREST_SIMPLE_TRANSPARENCY (0)
#endif

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9b6abac1d09714922b174070c93c9054
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,26 @@
//
// This file was automatically generated. Please don't edit by hand. Execute Editor command [ Edit > Rendering > Generate Shader Includes ] instead
//
#ifndef SETTINGS_CREST_SERVER_HLSL
#define SETTINGS_CREST_SERVER_HLSL
//
// WaveHarmonic.Crest.Editor.ShaderSettingsServer: static fields
//
#define CREST_ALBEDO_SIMULATION (1)
#define CREST_ABSORPTION_SIMULATION (1)
#define CREST_SCATTERING_SIMULATION (1)
#define CREST_SHADOW_SIMULATION (1)
#define CREST_OUT_SCATTERING (1)
#define CREST_NORMAL_MAPS (1)
#define CREST_PLANAR_REFLECTIONS (1)
#define CREST_PLANAR_REFLECTIONS_APPLY_SMOOTHNESS (1)
#define CREST_FOAM_SAMPLING_MULTI_SCALE (1)
#define CREST_FOAM_SAMPLING_STOCHASTIC (0)
#define CREST_FOAM_BIOLUMINESCENCE (1)
#define CREST_CAUSTICS_FORCE_DISTORTION (1)
#define CREST_ADDITIONAL_LIGHTS (1)
#define CREST_SIMPLE_TRANSPARENCY (0)
#endif

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 15a7369ec789c4ae08ac764eab29463e
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,26 @@
//
// This file was automatically generated. Please don't edit by hand. Execute Editor command [ Edit > Rendering > Generate Shader Includes ] instead
//
#ifndef SETTINGS_CREST_STANDALONE_HLSL
#define SETTINGS_CREST_STANDALONE_HLSL
//
// WaveHarmonic.Crest.Editor.ShaderSettingsStandalone: static fields
//
#define CREST_ALBEDO_SIMULATION (1)
#define CREST_ABSORPTION_SIMULATION (1)
#define CREST_SCATTERING_SIMULATION (1)
#define CREST_SHADOW_SIMULATION (1)
#define CREST_OUT_SCATTERING (1)
#define CREST_NORMAL_MAPS (1)
#define CREST_PLANAR_REFLECTIONS (1)
#define CREST_PLANAR_REFLECTIONS_APPLY_SMOOTHNESS (1)
#define CREST_FOAM_SAMPLING_MULTI_SCALE (1)
#define CREST_FOAM_SAMPLING_STOCHASTIC (0)
#define CREST_FOAM_BIOLUMINESCENCE (1)
#define CREST_CAUSTICS_FORCE_DISTORTION (1)
#define CREST_ADDITIONAL_LIGHTS (1)
#define CREST_SIMPLE_TRANSPARENCY (0)
#endif

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d9f563484a71c4e04a3aefcbef8ce36a
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,26 @@
//
// This file was automatically generated. Please don't edit by hand. Execute Editor command [ Edit > Rendering > Generate Shader Includes ] instead
//
#ifndef SETTINGS_CREST_WEB_HLSL
#define SETTINGS_CREST_WEB_HLSL
//
// WaveHarmonic.Crest.Editor.ShaderSettingsWeb: static fields
//
#define CREST_ALBEDO_SIMULATION (0)
#define CREST_ABSORPTION_SIMULATION (0)
#define CREST_SCATTERING_SIMULATION (0)
#define CREST_SHADOW_SIMULATION (0)
#define CREST_OUT_SCATTERING (1)
#define CREST_NORMAL_MAPS (1)
#define CREST_PLANAR_REFLECTIONS (0)
#define CREST_PLANAR_REFLECTIONS_APPLY_SMOOTHNESS (1)
#define CREST_FOAM_SAMPLING_MULTI_SCALE (1)
#define CREST_FOAM_SAMPLING_STOCHASTIC (0)
#define CREST_FOAM_BIOLUMINESCENCE (0)
#define CREST_CAUSTICS_FORCE_DISTORTION (0)
#define CREST_ADDITIONAL_LIGHTS (1)
#define CREST_SIMPLE_TRANSPARENCY (0)
#endif

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 0eecd007d82c74bf88658c84586cda62
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,26 @@
//
// This file was automatically generated. Please don't edit by hand. Execute Editor command [ Edit > Rendering > Generate Shader Includes ] instead
//
#ifndef SETTINGS_CREST_HLSL
#define SETTINGS_CREST_HLSL
//
// WaveHarmonic.Crest.Editor.ShaderSettings: static fields
//
#define CREST_PACKAGE_HDRP (1)
#define CREST_PACKAGE_URP (1)
#define CREST_PORTALS (0)
#define CREST_SHIFTING_ORIGIN (0)
#define CREST_PLATFORM_STANDALONE (1)
#define CREST_PLATFORM_SERVER (0)
#define CREST_PLATFORM_ANDROID (0)
#define CREST_PLATFORM_IOS (0)
#define CREST_PLATFORM_WEB (0)
#define CREST_PLATFORM_TVOS (0)
#define CREST_PLATFORM_VISIONOS (0)
#define CREST_FULL_PRECISION_DISPLACEMENT (1)
#define CREST_DISCARD_ATMOSPHERIC_SCATTERING (1)
#define CREST_LEGACY_UNDERWATER (0)
#endif

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b25f99570a3c543dca0d91bc54a4e27e
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,26 @@
//
// This file was automatically generated. Please don't edit by hand. Execute Editor command [ Edit > Rendering > Generate Shader Includes ] instead
//
#ifndef SETTINGS_CREST_IOS_HLSL
#define SETTINGS_CREST_IOS_HLSL
//
// WaveHarmonic.Crest.Editor.ShaderSettingsIOS: static fields
//
#define CREST_ALBEDO_SIMULATION (1)
#define CREST_ABSORPTION_SIMULATION (1)
#define CREST_SCATTERING_SIMULATION (1)
#define CREST_SHADOW_SIMULATION (1)
#define CREST_OUT_SCATTERING (1)
#define CREST_NORMAL_MAPS (1)
#define CREST_PLANAR_REFLECTIONS (1)
#define CREST_PLANAR_REFLECTIONS_APPLY_SMOOTHNESS (1)
#define CREST_FOAM_SAMPLING_MULTI_SCALE (1)
#define CREST_FOAM_SAMPLING_STOCHASTIC (0)
#define CREST_FOAM_BIOLUMINESCENCE (1)
#define CREST_CAUSTICS_FORCE_DISTORTION (1)
#define CREST_ADDITIONAL_LIGHTS (1)
#define CREST_SIMPLE_TRANSPARENCY (0)
#endif

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9d8991669495c4da8b6d2d9c62dadcb1
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,26 @@
//
// This file was automatically generated. Please don't edit by hand. Execute Editor command [ Edit > Rendering > Generate Shader Includes ] instead
//
#ifndef SETTINGS_CREST_TVOS_HLSL
#define SETTINGS_CREST_TVOS_HLSL
//
// WaveHarmonic.Crest.Editor.ShaderSettingsTVOS: static fields
//
#define CREST_ALBEDO_SIMULATION (1)
#define CREST_ABSORPTION_SIMULATION (1)
#define CREST_SCATTERING_SIMULATION (1)
#define CREST_SHADOW_SIMULATION (1)
#define CREST_OUT_SCATTERING (1)
#define CREST_NORMAL_MAPS (1)
#define CREST_PLANAR_REFLECTIONS (1)
#define CREST_PLANAR_REFLECTIONS_APPLY_SMOOTHNESS (1)
#define CREST_FOAM_SAMPLING_MULTI_SCALE (1)
#define CREST_FOAM_SAMPLING_STOCHASTIC (0)
#define CREST_FOAM_BIOLUMINESCENCE (1)
#define CREST_CAUSTICS_FORCE_DISTORTION (1)
#define CREST_ADDITIONAL_LIGHTS (1)
#define CREST_SIMPLE_TRANSPARENCY (0)
#endif

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: bff51ef931a4443a7b6c1a2fc2b88772
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,26 @@
//
// This file was automatically generated. Please don't edit by hand. Execute Editor command [ Edit > Rendering > Generate Shader Includes ] instead
//
#ifndef SETTINGS_CREST_VISIONOS_HLSL
#define SETTINGS_CREST_VISIONOS_HLSL
//
// WaveHarmonic.Crest.Editor.ShaderSettingsVisionOS: static fields
//
#define CREST_ALBEDO_SIMULATION (1)
#define CREST_ABSORPTION_SIMULATION (1)
#define CREST_SCATTERING_SIMULATION (1)
#define CREST_SHADOW_SIMULATION (1)
#define CREST_OUT_SCATTERING (1)
#define CREST_NORMAL_MAPS (1)
#define CREST_PLANAR_REFLECTIONS (1)
#define CREST_PLANAR_REFLECTIONS_APPLY_SMOOTHNESS (1)
#define CREST_FOAM_SAMPLING_MULTI_SCALE (1)
#define CREST_FOAM_SAMPLING_STOCHASTIC (0)
#define CREST_FOAM_BIOLUMINESCENCE (1)
#define CREST_CAUSTICS_FORCE_DISTORTION (1)
#define CREST_ADDITIONAL_LIGHTS (1)
#define CREST_SIMPLE_TRANSPARENCY (0)
#endif

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d0648a06882284ebc88f4b28f3c6f825
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,25 @@
//
// This file was automatically generated. Please don't edit by hand. Execute Editor command [ Edit > Rendering > Generate Shader Includes ] instead
//
#ifndef VISUALIZE_CREST_HLSL
#define VISUALIZE_CREST_HLSL
//
// WaveHarmonic.Crest.VisualizeDataTypes: static fields
//
#define VISUALIZEDATATYPES_ALBEDO (0)
#define VISUALIZEDATATYPES_DISPLACEMENT (1)
#define VISUALIZEDATATYPES_DYNAMIC_WAVES (2)
#define VISUALIZEDATATYPES_LEVEL (3)
#define VISUALIZEDATATYPES_FLOW (4)
#define VISUALIZEDATATYPES_FOAM (5)
#define VISUALIZEDATATYPES_SHADOW (6)
#define VISUALIZEDATATYPES_DEPTH (7)
#define VISUALIZEDATATYPES_CLIP (8)
#define VISUALIZEDATATYPES_SHORELINE_DISTANCE (9)
#define VISUALIZEDATATYPES_ABSORPTION (10)
#define VISUALIZEDATATYPES_SCATTERING (11)
#define VISUALIZEDATATYPES_CASCADES (12)
#endif

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 203c716a84722424d815f344a326e315
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -15,6 +15,7 @@
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Macros.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Globals.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/InputsDriven.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Utility/Stochastic.hlsl"
#ifdef SHADER_API_PSSL
#define m_ConstantReturn const
@@ -62,6 +63,11 @@ struct TiledTexture
{
return SAMPLE_TEXTURE2D_LOD(_texture, _sampler, uv, lod);
}
half4 SampleStochastic(float2 uv) m_ConstantReturn
{
return Utility::SampleStochastic(_texture, _sampler, uv);
}
};
m_CrestNameSpaceEnd

View File

@@ -8,6 +8,36 @@
m_UtilityNameSpace
// NOTE: We have to roll our own bilinear filter in Compute shaders when
// reading from a RWTexture. The documentation below explains how SRV
// and UAV mappings of the same texture cannot exist at the same time.
// https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/sm5-object-rwtexture2d
float4 SampleBilinear(const RWTexture2DArray<float4> i_Texture, const float2 i_UV, const uint i_Slice, const float i_Resolution)
{
// Make relative to pixel centers.
const float2 center = i_UV * i_Resolution - 0.5;
// Compute integral (bottom left) and fractional parts
// Prevent overflow from possible negative cast to unsigned.
const uint maximum = (uint)i_Resolution - 1;
const uint2 integral = max((float2)0.0, floor(center));
const uint2 opposite = uint2(min(integral.x + 1, maximum), min(integral.y + 1, maximum));
const float2 fractional = frac(center);
// Clamp from below and above (desired?).
const float4 bl = i_Texture[uint3(integral, i_Slice)];
const float4 br = i_Texture[uint3(uint2(opposite.x, integral.y), i_Slice)];
const float4 tl = i_Texture[uint3(uint2(integral.x, opposite.y), i_Slice)];
const float4 tr = i_Texture[uint3(opposite, i_Slice)];
return lerp
(
lerp(bl, br, fractional.x),
lerp(tl, tr, fractional.x),
fractional.y
);
}
// Taken from:
// https://gist.github.com/TheRealMJP/c83b8c0f46b63f3a88a5986f4fa982b1
//
@@ -66,6 +96,67 @@ float4 SampleTextureCatmullRom(in Texture2D<float4> tex, in SamplerState linearS
return result;
}
float4 CubicWeights(const float f)
{
const float f2 = f * f;
const float f3 = f2 * f;
// CatmullRom (a = -0.5)
return float4
(
-0.5 * f3 + f2 - 0.5 * f,
1.5 * f3 - 2.5 * f2 + 1.0,
-1.5 * f3 + 2.0 * f2 + 0.5 * f,
0.5 * f3 - 0.5 * f2
);
}
float4 SampleBicubicRepeat
(
const Texture2DArray<float4> i_Texture,
const float2 i_UV,
const uint2 i_Size,
const uint i_Slice
)
{
// Convert to texel space (centered at pixel centers).
const float2 samplePosition = i_UV * (float2)i_Size - 0.5;
const int2 texelPosition = (int2)floor(samplePosition);
const float2 f = samplePosition - (float2)texelPosition;
// Precompute weights.
const float4 wx = CubicWeights(f.x);
const float4 wy = CubicWeights(f.y);
const uint2 size = i_Size - 1;
const uint4 x = uint4
(
(texelPosition.x - 1) & size.x,
(texelPosition.x + 0) & size.x,
(texelPosition.x + 1) & size.x,
(texelPosition.x + 2) & size.x
);
// Horizontal pass.
float4 row[4];
[unroll]
for (int j = -1; j <= 2; ++j)
{
const int y = (texelPosition.y + j) & size.y;
const float4 t0 = i_Texture[uint3(x.x, y, i_Slice)];
const float4 t1 = i_Texture[uint3(x.y, y, i_Slice)];
const float4 t2 = i_Texture[uint3(x.z, y, i_Slice)];
const float4 t3 = i_Texture[uint3(x.w, y, i_Slice)];
row[j + 1] = t0 * wx.x + t1 * wx.y + t2 * wx.z + t3 * wx.w;
}
// Vertical pass.
return row[0] * wy.x + row[1] * wy.y + row[2] * wy.z + row[3] * wy.w;
}
m_UtilityNameSpaceEnd
#endif // d_WaveHarmonic_Utility_Filtering

View File

@@ -43,6 +43,16 @@ float2 WorldNormalToScreenDirection(const float3 i_PositionWS, const float3 i_No
return direction;
}
float3 SafeComputeWorldSpacePosition(float2 positionNDC, float deviceDepth, float4x4 invViewProjMatrix)
{
float4 positionCS = ComputeClipSpacePosition(positionNDC, deviceDepth);
float4 hpositionWS = mul(invViewProjMatrix, positionCS);
// w is sometimes zero when using oblique projection.
// Zero is better than NaN.
return hpositionWS.w > 0.0 ? hpositionWS.xyz / hpositionWS.w : 0.0;
}
m_UtilityNameSpaceEnd
#endif // d_WaveHarmonic_Utility_Helpers

View File

@@ -26,6 +26,15 @@
#define SHADERPASS_MOTION_VECTORS (22)
//
// Motion Vector Pass Fix
//
#if SHADERPASS == SHADERPASS_MOTION_VECTORS
#undef VARYINGS_NEED_NORMAL_WS
#endif
//
// Deferred Fix
//
@@ -86,6 +95,9 @@
// Transparent Objects Receives Shadows
//
// WebGPU does not like the binding.
#ifndef SHADER_API_WEBGPU
#if _SURFACE_TYPE_TRANSPARENT
#if _TRANSPARENT_RECEIVES_SHADOWS
#if SHADERPASS == SHADERPASS_FORWARD || SHADERPASS == SHADERPASS_FORWARD_ADD
@@ -108,4 +120,6 @@ float4 _ShadowMapTexture_TexelSize;
#endif
#endif
#endif // SHADER_API_WEBGPU
#endif // d_WaveHarmonic_Utility_ShaderGraphDefines

View File

@@ -21,39 +21,155 @@
#define CLUSTER_LIGHT_LOOP_SUBTRACTIVE_LIGHT_CHECK FORWARD_PLUS_SUBTRACTIVE_LIGHT_CHECK
#endif // FORWARD_PLUS_SUBTRACTIVE_LIGHT_CHECK
#if UNITY_VERSION >= 60000000
#if defined(STEREO_INSTANCING_ON) || defined(STEREO_MULTIVIEW_ON)
#if _ALPHATEST_ON
#if !USE_CLUSTER_LIGHT_LOOP
// If not clustered and additional light shadows and XR, the shading model
// completely breaks. It is like shadow attenuation is NaN or some obscure
// compiler issue. For 2022.3, it is broken for forward+ only, but cannot be fixed.
#define d_ShadowMaskBroken 1
#else
#if _RECEIVE_SHADOWS_OFF
// Right eye broken rendering similar to above.
#define d_AdditionalLightsBroken 1
#endif
#endif
#endif
#endif
#endif
#endif // CREST_URP
#if CREST_HDRP
#if CREST_HDRP_FORWARD_PASS
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
#if UNITY_VERSION < 202310
#define GetMeshRenderingLayerMask GetMeshRenderingLightLayer
#endif // UNITY_VERSION
#if d_Crest_AdditionalLights
#if d_Crest_WaterSurface
// Causes rendering issues at a distance with foreground objects.
#ifndef LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
#define LIGHTLOOP_DISABLE_TILE_AND_CLUSTER 1
#define d_Crest_LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
#endif // LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
m_CrestNameSpace
// Adapted from: com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.hlsl
half3 GetPunctualLights(float3 i_PositionWS, float2 i_PositionSS, const float4 i_ScreenPosition, const half3 i_Normal)
{
half3 color = 0.0;
BuiltinData builtinData;
ZERO_INITIALIZE(BuiltinData, builtinData);
LightLoopContext context;
context.sampleReflection = 0;
context.shadowContext = InitShadowContext();
context.contactShadow = 0;
context.contactShadowFade = 0.0;
context.shadowValue = 1;
#if UNITY_VERSION < 60000000
context.splineVisibility = -1;
#endif
#ifdef APPLY_FOG_ON_SKY_REFLECTIONS
context.positionWS = i_PositionWS;
#endif
float3 positionWS = GetCameraRelativePositionWS(i_PositionWS);
ApplyCameraRelativeXR(positionWS);
PositionInputs posInput;
ZERO_INITIALIZE(PositionInputs, posInput);
posInput.tileCoord = uint2(i_PositionSS) / GetTileSize();
posInput.positionWS = positionWS;
posInput.positionSS = i_PositionSS;
posInput.positionNDC = i_ScreenPosition.xy / i_ScreenPosition.w;
const uint renderingLayers = GetMeshRenderingLayerMask();
uint lightCount, lightStart;
#ifndef LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
GetCountAndStart(posInput, LIGHTCATEGORY_PUNCTUAL, lightStart, lightCount);
#else // LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
lightCount = _PunctualLightCount;
lightStart = 0;
#endif
bool fastPath = false;
#if SCALARIZE_LIGHT_LOOP
uint lightStartLane0;
fastPath = IsFastPath(lightStart, lightStartLane0);
if (fastPath)
{
lightStart = lightStartLane0;
}
#endif
// Scalarized loop. All lights that are in a tile/cluster touched by any pixel in the wave are loaded (scalar load), only the one relevant to current thread/pixel are processed.
// For clarity, the following code will follow the convention: variables starting with s_ are meant to be wave uniform (meant for scalar register),
// v_ are variables that might have different value for each thread in the wave (meant for vector registers).
// This will perform more loads than it is supposed to, however, the benefits should offset the downside, especially given that light data accessed should be largely coherent.
// Note that the above is valid only if wave intriniscs are supported.
uint v_lightListOffset = 0;
uint v_lightIdx = lightStart;
#if NEED_TO_CHECK_HELPER_LANE
// On some platform helper lanes don't behave as we'd expect, therefore we prevent them from entering the loop altogether.
// IMPORTANT! This has implications if ddx/ddy is used on results derived from lighting, however given Lightloop is called in compute we should be
// sure it will not happen.
bool isHelperLane = WaveIsHelperLane();
while (!isHelperLane && v_lightListOffset < lightCount)
#else
while (v_lightListOffset < lightCount)
#endif
{
v_lightIdx = FetchIndex(lightStart, v_lightListOffset);
#if SCALARIZE_LIGHT_LOOP
uint s_lightIdx = ScalarizeElementIndex(v_lightIdx, fastPath);
#else
uint s_lightIdx = v_lightIdx;
#endif
if (s_lightIdx == -1)
{
break;
}
LightData s_light = FetchLight(s_lightIdx);
// If current scalar and vector light index match, we process the light. The v_lightListOffset for current thread is increased.
// Note that the following should really be ==, however, since helper lanes are not considered by WaveActiveMin, such helper lanes could
// end up with a unique v_lightIdx value that is smaller than s_lightIdx hence being stuck in a loop. All the active lanes will not have this problem.
if (s_lightIdx >= v_lightIdx)
{
v_lightListOffset++;
if (IsMatchingLightLayer(s_light.lightLayers, renderingLayers))
{
float3 L; float4 distances; // {d, d^2, 1/d, d_proj}
GetPunctualLightVectors(positionWS, s_light, L, distances);
// Is it worth evaluating the light?
if (s_light.lightDimmer > 0)
{
float4 lightColor = EvaluateLight_Punctual(context, posInput, s_light, L, distances);
lightColor.rgb *= lightColor.a * max(k_Crest_AdditionalLightLerp, dot(i_Normal, L)); // Composite
SHADOW_TYPE shadow = EvaluateShadow_Punctual(context, posInput, s_light, builtinData, i_Normal, L, distances);
lightColor.rgb *= ComputeShadowColor(shadow, s_light.shadowTint, s_light.penumbraTint);
color += lightColor.rgb;
}
}
}
}
return color;
}
m_CrestNameSpaceEnd
#ifdef d_Crest_LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
#undef LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
#endif
#endif // d_Crest_WaterSurface
#endif // d_Crest_AdditionalLights
#if UNITY_VERSION < 60000000
#if PROBE_VOLUMES_L1
// URP sets this to zero.
#define AMBIENT_PROBE_BUFFER 1
#endif // PROBE_VOLUMES_L1
#endif // UNITY_VERSION
#endif // CREST_HDRP
#endif // CREST_HDRP_FORWARD_PASS
m_CrestNameSpace
@@ -64,13 +180,19 @@ void PrimaryLight
out half3 o_Direction
)
{
#if CREST_HDRP
// We could get the main light the same way we get the main light shadows,
// but most of the data would be missing (including below horizon
// attenuation) which would require re-running the light loop which is expensive.
o_Direction = g_Crest_PrimaryLightDirection;
o_Color = g_Crest_PrimaryLightIntensity;
#elif CREST_URP
o_Direction = half3(0.0, 1.0, 0.0);
o_Color = 0.0;
#ifndef d_IsAdditionalLight
if (g_Crest_PrimaryLightFallback)
{
o_Direction = g_Crest_PrimaryLightDirection;
o_Color = g_Crest_PrimaryLightIntensity;
return;
}
#endif
#if CREST_URP
// Actual light data from the pipeline.
Light light = GetMainLight();
o_Direction = light.direction;
@@ -78,7 +200,10 @@ void PrimaryLight
#elif CREST_BIRP
#ifndef USING_DIRECTIONAL_LIGHT
// Yes. This function wants the world position of the surface.
o_Direction = normalize(UnityWorldSpaceLightDir(i_PositionWS));
o_Direction = UnityWorldSpaceLightDir(i_PositionWS);
// Prevents divide by zero.
if (all(o_Direction == 0)) o_Direction = half3(0.0, 1.0, 0.0);
o_Direction = normalize(o_Direction);
#else
o_Direction = _WorldSpaceLightPos0.xyz;
// Prevents divide by zero.
@@ -100,7 +225,7 @@ half3 AmbientLight(const half3 i_AmbientLight)
half3 ambient = i_AmbientLight;
#ifndef SHADERGRAPH_PREVIEW
#if CREST_HDRP
#if CREST_HDRP_FORWARD_PASS
// Allows control of baked lighting through volume framework.
// We could create a BuiltinData struct which would have rendering layers on it, but it seems more complicated.
ambient *= GetIndirectDiffuseMultiplier(GetMeshRenderingLayerMask());
@@ -123,7 +248,9 @@ half3 AmbientLight()
return AmbientLight(ambient);
}
half3 AdditionalLighting(const float3 i_PositionWS, const float4 i_ScreenPosition, const float2 i_StaticLightMapUV)
#if d_Crest_AdditionalLights
#if d_Crest_WaterSurface
half3 AdditionalLighting(const float3 i_PositionWS, const float4 i_ScreenPosition, const float2 i_StaticLightMapUV, const float2 i_PositionSS, const half3 i_Normal)
{
half3 color = 0.0;
@@ -153,19 +280,11 @@ LIGHT_LOOP_BEGIN(pixelLightCount)
// Includes shadows and cookies.
Light light = GetAdditionalLight(lightIndex, inputData, shadowMask, aoFactor);
#if d_ShadowMaskBroken
light.shadowAttenuation = 1.0;
#endif
#if d_AdditionalLightsBroken
light.color = 0.0;
#endif
#ifdef _LIGHT_LAYERS
if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
#endif
{
color += light.color * (light.distanceAttenuation * light.shadowAttenuation);
color += light.color * max(k_Crest_AdditionalLightLerp, dot(i_Normal, light.direction)) * (light.distanceAttenuation * light.shadowAttenuation);
}
LIGHT_LOOP_END
@@ -188,11 +307,16 @@ LIGHT_LOOP_END
#endif // _ADDITIONAL_LIGHTS
#endif // CREST_URP
// HDRP todo.
#if CREST_HDRP_FORWARD_PASS
color = GetPunctualLights(i_PositionWS, i_PositionSS, i_ScreenPosition, i_Normal);
#endif
// BIRP has additional lights as additional passes. Handled elsewhere.
return color;
}
#endif // d_Crest_WaterSurface
#endif // d_Crest_AdditionalLights
m_CrestNameSpaceEnd

View File

@@ -0,0 +1,67 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
// Adapted from:
// https://pastebin.com/sDrnzYxB
// License:
// CC0 Creative Commons License
// "Yes by all means use it how you wish. I'm sharing it as CC0."
// https://www.reddit.com/r/Unity3D/comments/dhr5g2/comment/f3rz6rc/
#ifndef d_WaveHarmonic_Utility_Stochastic
#define d_WaveHarmonic_Utility_Stochastic
m_UtilityNameSpace
float2 Hash2D2D(const float2 s)
{
// Magic numbers.
return frac(sin(fmod(float2(dot(s, float2(127.1, 311.7)), dot(s, float2(269.5, 183.3))), PI)) * 43758.5453);
}
float4 SampleStochastic(const Texture2D i_Texture, const SamplerState i_Sampler, const float2 i_UV)
{
// UV transformed into triangular grid space with UV scaled by approximation of 2 * sqrt(3)
const float2 skewUV = mul(float2x2(1.0, 0.0, -0.57735027, 1.15470054), i_UV * 3.464);
// Vertex IDs and barycentric coords
const float2 id = float2(floor(skewUV));
float3 barry = float3(frac(skewUV), 0.0);
barry.z = 1.0 - barry.x - barry.y;
// Triangle vertices and blend weights.
// BW_vx[0...2].xyz = triangle verts
// BW_vx[3].xy = blend weights (z is unused)
const float4x3 BW_vx =
(
(barry.z > 0)
? float4x3
(
float3(id, 0),
float3(id + float2(0, 1), 0),
float3(id + float2(1, 0), 0),
barry.zyx
)
: float4x3
(
float3(id + float2(1, 1), 0),
float3(id + float2(1, 0), 0),
float3(id + float2(0, 1), 0),
float3(-barry.z, 1.0 - barry.y, 1.0 - barry.x)
)
);
// Calculate derivatives to avoid triangular grid artifacts.
const float2 dx = ddx(i_UV);
const float2 dy = ddy(i_UV);
// Blend samples with calculated weights.
return SAMPLE_TEXTURE2D_GRAD(i_Texture, i_Sampler, i_UV + Hash2D2D(BW_vx[0].xy), dx, dy) * BW_vx[3].x +
SAMPLE_TEXTURE2D_GRAD(i_Texture, i_Sampler, i_UV + Hash2D2D(BW_vx[1].xy), dx, dy) * BW_vx[3].y +
SAMPLE_TEXTURE2D_GRAD(i_Texture, i_Sampler, i_UV + Hash2D2D(BW_vx[2].xy), dx, dy) * BW_vx[3].z;
}
m_UtilityNameSpaceEnd
#endif // d_WaveHarmonic_Utility_Stochastic

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 90b04c86b94da4f6890d04a7b7fa5226
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e2302652cd9694fd8aa17d8c3de60002
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,119 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
// d_WaterLevelDisplacementOnly
// d_RequirePositionWS
// d_RequireUndisplacedXZ
#ifndef d_WaveHarmonic_Crest_LibraryVertexSurface
#define d_WaveHarmonic_Crest_LibraryVertexSurface
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Settings.Crest.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Macros.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Constants.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/InputsDriven.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Globals.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Helpers.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Cascade.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Geometry.hlsl"
m_CrestNameSpace
struct Attributes
{
float3 _PositionOS : POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 _PositionCS : SV_POSITION;
#if d_RequirePositionWS
float3 _PositionWS : TEXCOORD;
#endif
#if d_RequireUndisplacedXZ
float2 _UndispacedPositionXZ : TEXCOORD1;
#endif
#if d_RequireLodAlpha
float _LodAlpha : TEXCOORD2;
#endif
UNITY_VERTEX_OUTPUT_STEREO
};
Varyings Vertex(const Attributes i_Input)
{
// This will work for all pipelines.
Varyings output = (Varyings)0;
UNITY_SETUP_INSTANCE_ID(i_Input);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
const uint slice0 = _Crest_LodIndex;
const uint slice1 = slice0 + 1;
const Cascade cascade0 = Cascade::Make(slice0);
const Cascade cascade1 = Cascade::Make(slice1);
float3 positionWS = mul(UNITY_MATRIX_M, float4(i_Input._PositionOS, 1.0)).xyz;
#if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0)
positionWS.xz += _WorldSpaceCameraPos.xz;
#endif
float alpha;
SnapAndTransitionVertLayout(_Crest_ChunkMeshScaleAlpha, cascade0, _Crest_ChunkGeometryGridWidth, positionWS, alpha);
{
float2 center = UNITY_MATRIX_M._m03_m23;
#if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0)
center += _WorldSpaceCameraPos.xz;
#endif
PatchVerticeLayout(center, _WorldSpaceCameraPos.xz, positionWS.xz);
}
const float weight0 = (1.0 - alpha) * cascade0._Weight;
const float weight1 = (1.0 - weight0) * cascade1._Weight;
const float2 undisplaced = positionWS.xz;
float4 displacement = 0.0;
// Data that needs to be sampled at the undisplaced position.
if (weight0 > m_CrestSampleLodThreshold)
{
Cascade::MakeAnimatedWaves(slice0).SampleAnimatedWaves(undisplaced, weight0, displacement);
}
if (weight1 > m_CrestSampleLodThreshold)
{
Cascade::MakeAnimatedWaves(slice1).SampleAnimatedWaves(undisplaced, weight1, displacement);
}
#if !d_WaterLevelDisplacementOnly
positionWS += displacement.xyz;
#endif
positionWS.y += displacement.w;
#if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0)
positionWS.xz -= _WorldSpaceCameraPos.xz;
#endif
output._PositionCS = mul(UNITY_MATRIX_VP, float4(positionWS, 1.0));
#if d_RequirePositionWS
output._PositionWS = positionWS;
#endif
#if d_RequireUndisplacedXZ
output._UndispacedPositionXZ = undisplaced;
#endif
#if d_RequireLodAlpha
output._LodAlpha = alpha;
#endif
return output;
}
m_CrestNameSpaceEnd
#endif // d_WaveHarmonic_Crest_LibraryVertexSurface

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d3db8590d951749189fc4e97bddb42c5
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -11,8 +11,6 @@
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Utility/Depth.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Globals.hlsl"
float2 _Crest_HorizonNormal;
TEXTURE2D_X(_Crest_WaterMaskTexture);
m_CrestNameSpace
@@ -45,7 +43,7 @@ half4 Fragment(Varyings input)
const uint2 positionSS = input.positionCS.xy;
const float mask = LOAD_TEXTURE2D_X(_Crest_WaterMaskTexture, positionSS).x;
const float2 offset = -((float2)mask) * _Crest_HorizonNormal;
const float2 offset = -((float2)mask) * g_Crest_HorizonNormal;
float weight = 1.0;
// Sample three pixels along the normal. If the sample is different than the

View File

@@ -13,6 +13,7 @@
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Utility/Depth.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Shim.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Keywords.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Utility/Lighting.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/VolumeLighting.hlsl"
@@ -34,12 +35,14 @@ half _Crest_ShadowsAffectsAmbientFactor;
// Volume parameters.
half _Crest_SunBoost;
half3 _Crest_AmbientLighting;
int _Crest_DataSliceOffset;
uint _Crest_DataSliceOffset;
#endif
half _Crest_Radius;
half _Crest_RefractionStrength;
bool _Crest_PortalInverted;
m_CrestNameSpace
struct Attributes
@@ -87,7 +90,7 @@ half4 Fragment(Varyings input)
#if d_Masked
// Prevent rendering inside of new portal modules.
if (LOAD_TEXTURE2D_X(_Crest_WaterMaskTexture, input.positionCS.xy).r == k_Crest_MaskInsidePortal)
if ((LOAD_TEXTURE2D_X(_Crest_WaterMaskTexture, input.positionCS.xy).r == k_Crest_MaskInsidePortal) == _Crest_PortalInverted)
{
discard;
}
@@ -154,10 +157,21 @@ half4 Fragment(Varyings input)
half3 scattering = _Crest_Scattering.xyz;
// Keep the same as the volume.
const int sliceIndex = clamp(_Crest_DataSliceOffset, 0, g_Crest_LodCount - 2);
const uint sliceIndex = clamp(_Crest_DataSliceOffset, 0, g_Crest_LodCount - 2);
if (g_Crest_SampleAbsorptionSimulation) absorption = Cascade::MakeAbsorption(sliceIndex).Sample(_WorldSpaceCameraPos.xz).xyz;
if (g_Crest_SampleScatteringSimulation) scattering = Cascade::MakeScattering(sliceIndex).Sample(_WorldSpaceCameraPos.xz).xyz;
#if d_Crest_AbsorptionLod
if (g_Crest_SampleAbsorptionSimulation)
{
absorption = Cascade::MakeAbsorption(sliceIndex).Sample(_WorldSpaceCameraPos.xz).xyz;
}
#endif
#if d_Crest_ScatteringLod
if (g_Crest_SampleScatteringSimulation)
{
scattering = Cascade::MakeScattering(sliceIndex).Sample(_WorldSpaceCameraPos.xz).xyz;
}
#endif
float3 lightDirection; float3 lightColor;
PrimaryLight(positionWS, lightColor, lightDirection);
@@ -174,10 +188,13 @@ half4 Fragment(Varyings input)
#endif
half shadow = 1.0;
#if d_Crest_ShadowLod
{
// Soft in red, hard in green. But hard not computed in HDRP.
shadow = 1.0 - Cascade::MakeShadow(sliceIndex).SampleShadow(_WorldSpaceCameraPos.xz).x;
}
#endif
half3 lighting = VolumeLighting
(
@@ -190,8 +207,10 @@ half4 Fragment(Varyings input)
lerp(half3(0, -1, 0), lightDirection, opacity),
lightColor,
half3(0.0, 0.0, 0.0), // Additional lights
1.0, // Additional light blend
_Crest_AmbientTerm,
_Crest_DirectTerm,
1.0, // Additional light term
_Crest_SunBoost,
_Crest_ShadowsAffectsAmbientFactor
);

View File

@@ -16,7 +16,7 @@ float ClipSurface(const float2 i_PositionWSXZ)
{
// Do not include transition slice to avoid blending as we do a black border instead.
uint slice0; uint slice1; float alpha;
PosToSliceIndices(i_PositionWSXZ, 0.0, g_Crest_LodCount - 1.0, g_Crest_WaterScale, slice0, slice1, alpha);
PositionToSliceIndices(i_PositionWSXZ, 0, g_Crest_LodCount - 1, g_Crest_WaterScale, slice0, slice1, alpha);
const Cascade cascade0 = Cascade::Make(slice0);
const Cascade cascade1 = Cascade::Make(slice1);
@@ -34,7 +34,7 @@ float ClipSurface(const float2 i_PositionWSXZ)
Cascade::MakeClip(slice1).SampleClip(i_PositionWSXZ, weight1, value);
}
return lerp(g_Crest_ClipByDefault, value, weight0 + weight1);
return value;
}
m_CrestNameSpaceEnd

View File

@@ -77,6 +77,7 @@ half3 Caustics
);
}
#if d_Crest_CausticsForceDistortion
if (i_Underwater)
{
float2 surfacePosXZ = i_ScenePositionWS.xz;
@@ -93,6 +94,7 @@ half3 Caustics
cuv1.xy += 1.30 * causticN;
cuv2.xy += 1.77 * causticN;
}
#endif
half causticsStrength = i_Strength;

View File

@@ -12,28 +12,43 @@ TEXTURE2D_FLOAT(_Crest_WaterLine);
float _Crest_WaterLineTexel;
float2 _Crest_WaterLineResolution;
float2 _Crest_WaterLineSnappedPosition;
bool _Crest_WaterLineFlatWater;
m_CrestNameSpace
float SampleWaterLineHeight(const float2 i_PositionWS)
{
const float2 uv = (i_PositionWS - _Crest_WaterLineSnappedPosition) / (_Crest_WaterLineTexel * _Crest_WaterLineResolution) + 0.5;
return _Crest_WaterLine.SampleLevel(_Crest_linear_clamp_sampler, uv, 0).r + g_Crest_WaterCenter.y;
if (_Crest_WaterLineFlatWater)
{
return g_Crest_WaterCenter.y;
}
else
{
const float2 uv = (i_PositionWS - _Crest_WaterLineSnappedPosition) / (_Crest_WaterLineTexel * _Crest_WaterLineResolution) + 0.5;
return _Crest_WaterLine.SampleLevel(LODData_linear_clamp_sampler, uv, 0).r + g_Crest_WaterCenter.y;
}
}
half3 SampleWaterLineNormal(const float2 i_PositionWS, const float i_Height)
{
const float2 uv = (i_PositionWS - _Crest_WaterLineSnappedPosition) / (_Crest_WaterLineTexel * _Crest_WaterLineResolution) + 0.5;
const float3 dd = float3(1.0 / _Crest_WaterLineResolution.xy, 0.0);
const float xOffset = _Crest_WaterLine.SampleLevel(_Crest_linear_clamp_sampler, uv + dd.xz, 0).r;
const float zOffset = _Crest_WaterLine.SampleLevel(_Crest_linear_clamp_sampler, uv + dd.zy, 0).r;
if (_Crest_WaterLineFlatWater)
{
return half3(0, 1, 0);
}
else
{
const float2 uv = (i_PositionWS - _Crest_WaterLineSnappedPosition) / (_Crest_WaterLineTexel * _Crest_WaterLineResolution) + 0.5;
const float3 dd = float3(1.0 / _Crest_WaterLineResolution.xy, 0.0);
const float xOffset = _Crest_WaterLine.SampleLevel(LODData_linear_clamp_sampler, uv + dd.xz, 0).r;
const float zOffset = _Crest_WaterLine.SampleLevel(LODData_linear_clamp_sampler, uv + dd.zy, 0).r;
return normalize(half3
(
(xOffset - i_Height) / _Crest_WaterLineTexel,
1.0,
(zOffset - i_Height) / _Crest_WaterLineTexel
));
return normalize(half3
(
(xOffset - i_Height) / _Crest_WaterLineTexel,
1.0,
(zOffset - i_Height) / _Crest_WaterLineTexel
));
}
}
m_CrestNameSpaceEnd

View File

@@ -0,0 +1,52 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
#ifndef d_WaveHarmonic_Crest_Surface_Emission
#define d_WaveHarmonic_Crest_Surface_Emission
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Macros.hlsl"
m_CrestNameSpace
half3 FoamBioluminescence
(
const half i_FoamData,
const half i_FoamMap,
const half3 i_BioluminescenceColor,
const half i_BioluminescenceIntensity,
const half i_BioluminescenceGlowCoverage,
const half i_BioluminescenceGlowIntensity,
const bool i_BioluminescenceSparklesEnabled,
const half i_BioluminescenceSparklesMap,
const half i_BioluminescenceSparklesCoverage,
const half i_BioluminescenceSparklesIntensity,
const half i_BioluminescenceMaximumDepth,
const half i_WaterDepth
)
{
half3 emission = 0.0;
const half weight = 1.0 - saturate(i_WaterDepth / i_BioluminescenceMaximumDepth);
if (weight <= 0.0)
{
return emission;
}
emission +=
(i_BioluminescenceColor * i_FoamMap * i_BioluminescenceIntensity) +
(i_BioluminescenceColor * saturate(i_FoamData - (1.0 - i_BioluminescenceGlowCoverage)) * i_BioluminescenceGlowIntensity);
if (i_BioluminescenceSparklesEnabled)
{
emission += (i_BioluminescenceColor * i_BioluminescenceSparklesMap * saturate(i_FoamData - (1.0 - i_BioluminescenceSparklesCoverage)) * i_BioluminescenceSparklesIntensity);
}
emission *= weight;
return emission;
}
m_CrestNameSpaceEnd
#endif // d_WaveHarmonic_Crest_Surface_Emission

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 4707eb239a4b242d4ac074ac67b5544e
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -14,9 +14,15 @@
#include "Packages/com.waveharmonic.crest.shifting-origin/Runtime/Shaders/ShiftingOrigin.hlsl"
#endif
#if d_Crest_FoamStochastic
#define m_SampleFoam SampleStochastic
#else
#define m_SampleFoam Sample
#endif
m_CrestNameSpace
half WhiteFoamTexture
half2 WhiteFoamTexture
(
const TiledTexture i_Texture,
const half i_Foam,
@@ -25,27 +31,52 @@ half WhiteFoamTexture
const float2 i_WorldXZ1,
const float2 i_TexelOffset,
const half i_LodAlpha,
const Cascade i_CascadeData0
const Cascade i_CascadeData0,
const bool i_Sample2ndChannel = false
)
{
const float2 uvOffset = i_TexelOffset + g_Crest_Time * i_Texture._speed / 32.0;
// Scale with lods to get multiscale detail. 10 is magic number that gets the
// material 'scale' slider into an intuitive range.
const float scale = i_Texture._scale * i_CascadeData0._Scale / 10.0;
float scale = i_Texture._scale * 0.5;
half ft = lerp
(
i_Texture.Sample((i_WorldXZ0 + uvOffset) / scale).r,
i_Texture.Sample((i_WorldXZ1 + uvOffset) / (2.0 * scale)).r,
i_LodAlpha
);
#if d_Crest_FoamMultiScale
// 0.5 * 0.2 == / 10. We only need the full amount for multi-scale to account for
// the default lower scale of 4. * 0.5 alone above will not match multi-scaled, but
// overall better matches visually.
scale *= i_CascadeData0._Scale * 0.2;
#endif
half2 f0 = i_Texture.m_SampleFoam((i_WorldXZ0 + uvOffset) / scale).rg;
#if d_Crest_FoamMultiScale
const half2 f1 = i_Texture.m_SampleFoam((i_WorldXZ1 + uvOffset) / (2.0 * scale)).rg;
#endif
// Black point fade.
half result = saturate(1.0 - i_Foam);
return smoothstep(result, result + i_Feather, ft);
const half result = saturate(1.0 - i_Foam);
#if d_Crest_FoamBioluminescence
if (i_Sample2ndChannel)
{
#if d_Crest_FoamMultiScale
f0 = lerp(f0, f1, i_LodAlpha);
#endif
return smoothstep(result, result + i_Feather, f0);
}
else
#endif
{
#if d_Crest_FoamMultiScale
f0.r = lerp(f0.r, f1.r, i_LodAlpha);
#endif
return half2(smoothstep(result, result + i_Feather, f0.r), 0.0);
}
}
half MultiScaleFoamAlbedo
half2 MultiScaleFoamAlbedo
(
const TiledTexture i_Texture,
const half i_Feather,
@@ -53,7 +84,8 @@ half MultiScaleFoamAlbedo
const Cascade i_CascadeData0,
const Cascade i_CascadeData1,
const half i_LodAlpha,
const float2 i_UndisplacedXZ
const float2 i_UndisplacedXZ,
const bool i_Sample2ndChannel
)
{
float2 worldXZ0 = i_UndisplacedXZ;
@@ -67,20 +99,20 @@ half MultiScaleFoamAlbedo
worldXZ1 -= ShiftingOriginOffset(i_Texture, i_CascadeData1);
#endif // CREST_SHIFTING_ORIGIN
return WhiteFoamTexture(i_Texture, i_FoamData, i_Feather, worldXZ0, worldXZ1, (float2)0.0, i_LodAlpha, i_CascadeData0);
return WhiteFoamTexture(i_Texture, i_FoamData, i_Feather, worldXZ0, worldXZ1, (float2)0.0, i_LodAlpha, i_CascadeData0, i_Sample2ndChannel);
}
half2 MultiScaleFoamNormal
(
const TiledTexture i_Texture,
const half i_Feather,
const half i_NormalStrength,
const half i_FoamData,
const half i_FoamAlbedo,
const Cascade i_CascadeData0,
const Cascade i_CascadeData1,
const half i_LodAlpha,
const float2 i_UndisplacedXZ,
const half i_NormalStrength,
const half i_FoamAlbedo,
const float i_PixelZ
)
{
@@ -97,8 +129,8 @@ half2 MultiScaleFoamNormal
// 0.25 is magic number found through tweaking.
const float2 dd = float2(0.25 * i_PixelZ * i_Texture._texel, 0.0);
const half whiteFoam_x = WhiteFoamTexture(i_Texture, i_FoamData, i_Feather, worldXZ0, worldXZ1, dd.xy, i_LodAlpha, i_CascadeData0);
const half whiteFoam_z = WhiteFoamTexture(i_Texture, i_FoamData, i_Feather, worldXZ0, worldXZ1, dd.yx, i_LodAlpha, i_CascadeData0);
const half whiteFoam_x = WhiteFoamTexture(i_Texture, i_FoamData, i_Feather, worldXZ0, worldXZ1, dd.xy, i_LodAlpha, i_CascadeData0).r;
const half whiteFoam_z = WhiteFoamTexture(i_Texture, i_FoamData, i_Feather, worldXZ0, worldXZ1, dd.yx, i_LodAlpha, i_CascadeData0).r;
// Compute a foam normal - manually push in derivatives. If I used blend
// smooths all the normals towards straight up when there is no foam.
@@ -107,7 +139,7 @@ half2 MultiScaleFoamNormal
return magicStrengthFactor * i_NormalStrength * half2(whiteFoam_x - i_FoamAlbedo, whiteFoam_z - i_FoamAlbedo) / dd.x;
}
half MultiScaleFoamAlbedo
half2 MultiScaleFoamAlbedo
(
const Flow i_Flow,
const TiledTexture i_Texture,
@@ -116,7 +148,8 @@ half MultiScaleFoamAlbedo
const Cascade i_CascadeData0,
const Cascade i_CascadeData1,
const half i_LodAlpha,
const float2 i_UndisplacedXZ
const float2 i_UndisplacedXZ,
const bool i_Sample2ndChannel
)
{
return MultiScaleFoamAlbedo
@@ -127,7 +160,8 @@ half MultiScaleFoamAlbedo
i_CascadeData0,
i_CascadeData1,
i_LodAlpha,
i_UndisplacedXZ - i_Flow._Flow * i_Flow._Offset0
i_UndisplacedXZ - i_Flow._Flow * i_Flow._Offset0,
i_Sample2ndChannel
) * i_Flow._Weight0 + MultiScaleFoamAlbedo
(
i_Texture,
@@ -136,7 +170,8 @@ half MultiScaleFoamAlbedo
i_CascadeData0,
i_CascadeData1,
i_LodAlpha,
i_UndisplacedXZ - i_Flow._Flow * i_Flow._Offset1
i_UndisplacedXZ - i_Flow._Flow * i_Flow._Offset1,
i_Sample2ndChannel
) * i_Flow._Weight1;
}
@@ -145,13 +180,13 @@ half2 MultiScaleFoamNormal
const Flow i_Flow,
const TiledTexture i_Texture,
const half i_Feather,
const half i_NormalStrength,
const half i_FoamData,
const half i_FoamAlbedo,
const Cascade i_CascadeData0,
const Cascade i_CascadeData1,
const half i_LodAlpha,
const float2 i_UndisplacedXZ,
const half i_NormalStrength,
const half i_FoamAlbedo,
const float i_PixelZ
)
{
@@ -159,25 +194,25 @@ half2 MultiScaleFoamNormal
(
i_Texture,
i_Feather,
i_NormalStrength,
i_FoamData,
i_FoamAlbedo,
i_CascadeData0,
i_CascadeData1,
i_LodAlpha,
i_UndisplacedXZ - i_Flow._Flow * i_Flow._Offset0,
i_NormalStrength,
i_FoamAlbedo,
i_PixelZ
) * i_Flow._Weight0 + MultiScaleFoamNormal
(
i_Texture,
i_Feather,
i_NormalStrength,
i_FoamData,
i_FoamAlbedo,
i_CascadeData0,
i_CascadeData1,
i_LodAlpha,
i_UndisplacedXZ - i_Flow._Flow * i_Flow._Offset1,
i_NormalStrength,
i_FoamAlbedo,
i_PixelZ
) * i_Flow._Weight1;
}
@@ -214,8 +249,10 @@ void ApplyFoamToSurface
// as if it had transmission.
// There is still ugliness around the edges. There will either be black or
// incorrect reflections depending on the magic value.
io_NormalWS.y *= i_Foam > 0.15 ? -1.0 : 1.0;
io_NormalWS = i_Foam > 0.0 ? half3(0.0, 1.0, 0.0) : io_NormalWS;
#if _SPECULAR_SETUP
io_Specular = lerp(io_Specular, i_Specular, i_Foam);
#endif
}
}

View File

@@ -23,13 +23,31 @@ void SetUpFog(bool i_Underwater, float3 i_PositionWS, float i_Multiplier, float
{
s_IsUnderWater = i_Underwater;
// XR does not like early returns in URP.
#if !defined(STEREO_INSTANCING_ON) && !defined(STEREO_MULTIVIEW_ON)
if (!s_IsUnderWater)
{
return;
}
#endif
#if (CREST_LEGACY_UNDERWATER != 1)
s_PositionSS = i_PositionSS;
s_PositionWS = i_PositionWS;
s_ViewWS = i_ViewWS;
s_FogDistance = i_FogDistance;
s_DepthRaw = 0;
s_FogMultiplier = i_Multiplier;
ApplyUnderwaterEffect
(
0, // Not used (color)
0, // TIR only
0, // Caustics only
i_FogDistance,
i_ViewWS,
i_PositionSS,
i_PositionWS,
false, // No caustics
true, // TODO: implement
false, // Do not apply lighting
1.0, // TODO: implement
s_VolumeOpacity,
s_VolumeLighting
);
#endif
}

View File

@@ -4,11 +4,10 @@
// Guard against missing uniforms.
#ifdef SHADERPASS
#define m_Properties \
#define m_Properties(iomod) \
const float2 i_UndisplacedXZ, \
const float i_LodAlpha, \
float i_LodAlpha, \
const half i_WaterLevelOffset, \
const float2 i_WaterLevelDerivatives, \
const half2 i_Flow, \
const half3 i_ViewDirectionWS, \
const bool i_Facing, \
@@ -18,14 +17,38 @@
const float4 i_ScreenPositionRaw, \
const float3 i_PositionWS, \
const float3 i_PositionVS, \
const half3 i_NormalWS, \
const float2 i_StaticLightMapUV, \
out half3 o_Albedo, \
out half3 o_NormalWS, \
out half3 o_Specular, \
out half3 o_Emission, \
out half o_Smoothness, \
out half o_Occlusion, \
out half o_Alpha
iomod half3 o_Albedo, \
iomod half3 o_NormalWS, \
iomod half3 o_Specular, \
iomod half3 o_Emission, \
iomod half o_Smoothness, \
iomod half o_Occlusion, \
iomod half o_Alpha
#define m_Parameters \
i_UndisplacedXZ, \
i_LodAlpha, \
i_WaterLevelOffset, \
i_Flow, \
i_ViewDirectionWS, \
i_Facing, \
i_SceneColor, \
i_SceneDepthRaw, \
i_ScreenPosition, \
i_ScreenPositionRaw, \
i_PositionWS, \
i_PositionVS, \
i_NormalWS, \
i_StaticLightMapUV, \
o_Albedo, \
o_NormalWS, \
o_Specular, \
o_Emission, \
o_Smoothness, \
o_Occlusion, \
o_Alpha
// Guard against Shader Graph preview.
#ifndef SHADERGRAPH_PREVIEW
@@ -33,13 +56,13 @@
#define d_Crest_WaterSurface 1
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Shim.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Keywords.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Macros.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Globals.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/InputsDriven.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Cascade.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Geometry.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Utility/Depth.hlsl"
@@ -54,6 +77,7 @@
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Refraction.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Caustics.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/VolumeLighting.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Emission.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Fresnel.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Foam.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Alpha.hlsl"
@@ -79,17 +103,18 @@ static const TiledTexture _Crest_CausticsTiledTexture =
static const TiledTexture _Crest_CausticsDistortionTiledTexture =
TiledTexture::Make(_Crest_CausticsDistortionTexture, sampler_Crest_CausticsDistortionTexture, _Crest_CausticsDistortionTexture_TexelSize, _Crest_CausticsDistortionScale, 1.0);
void Fragment(m_Properties)
void Fragment
(
m_Properties(inout),
const uint i_LodIndex0,
const uint i_LodIndex1,
const float2 i_PositionSS,
const bool i_Underwater,
const float i_SceneZRaw,
const float i_NegativeFog
)
{
o_Albedo = 0.0;
o_NormalWS = half3(0.0, 1.0, 0.0);
o_Specular = 0.0;
o_Emission = 0.0;
o_Smoothness = 0.7;
o_Occlusion = 1.0;
o_Alpha = 1.0;
const float2 positionSS = i_ScreenPosition.xy * _ScreenSize.xy;
float2 scenePositionSS = i_PositionSS;
// Editor only. There is no defined editor symbol.
if (_Crest_DrawBoundaryXZ)
@@ -105,85 +130,99 @@ void Fragment(m_Properties)
}
}
bool underwater = IsUnderWater(i_Facing, g_Crest_ForceUnderwater, positionSS);
// TODO: Should we use PosToSIs or check for overflow?
float slice0 = _Crest_LodIndex;
float slice1 = _Crest_LodIndex + 1;
#ifdef CREST_FLOW_ON
const Flow flow = Flow::Make(i_Flow, g_Crest_Time);
#endif
const uint slice0 = i_LodIndex0;
const uint slice1 = i_LodIndex1;
const Cascade cascade0 = Cascade::Make(slice0);
const Cascade cascade1 = Cascade::Make(slice1);
float sceneRawZ = i_SceneDepthRaw;
float negativeFog = _ProjectionParams.y;
const float sceneZ = Utility::CrestLinearEyeDepth(i_SceneZRaw);
const float pixelZ = -i_PositionVS.z;
#if (CREST_PORTALS != 0)
#ifndef CREST_SHADOWPASS
#if _ALPHATEST_ON
if (m_CrestPortal)
{
const float pixelRawZ = i_ScreenPositionRaw.z / i_ScreenPositionRaw.w;
if (Portal::EvaluateSurface(i_ScreenPosition.xy, pixelRawZ, i_PositionWS, underwater, sceneRawZ, negativeFog))
{
o_Alpha = 0.0;
return;
}
}
#endif
#endif
#endif
float sceneZ = Utility::CrestLinearEyeDepth(sceneRawZ);
float pixelZ = -i_PositionVS.z;
const bool isLastLod = _Crest_LodIndex == (uint)g_Crest_LodCount - 1;
const bool isLastLod = slice0 == (g_Crest_LodCount - 1);
const float weight0 = (1.0 - i_LodAlpha) * cascade0._Weight;
const float weight1 = (1.0 - weight0) * cascade1._Weight;
// Data that fades towards the edge.
half foam = 0.0; half _determinant = 0.0; half4 albedo = 0.0; half2 shadow = 0.0;
half foam = 0.0; half _determinant = 0.0; half4 albedo = 0.0; half2 shadow = 0.0; half waterDepth = i_WaterLevelOffset; half shorelineDistance = 0.0; half2 flowData = 0.0;
if (weight0 > m_CrestSampleLodThreshold)
{
Cascade::MakeAnimatedWaves(slice0).SampleNormals(i_UndisplacedXZ, weight0, o_NormalWS.xz, _determinant);
if (_Crest_ApplyDisplacementNormals)
{
Cascade::MakeAnimatedWaves(slice0).SampleDisplacementNormal(i_UndisplacedXZ, weight0, o_NormalWS.xz, _determinant);
}
#if d_Crest_CustomMesh && d_Crest_FlowLod
Cascade::MakeFlow(slice0).SampleFlow(i_UndisplacedXZ, weight0, flowData);
#endif
if (_Crest_FoamEnabled)
{
Cascade::MakeFoam(slice0).SampleFoam(i_UndisplacedXZ, weight0, foam);
}
#if d_Crest_AlbedoLod
if (_Crest_AlbedoEnabled)
{
Cascade::MakeAlbedo(slice0).SampleAlbedo(i_UndisplacedXZ, weight0, albedo);
}
#endif
#if d_Crest_ShadowLod
if (_Crest_ShadowsEnabled)
{
Cascade::MakeShadow(slice0).SampleShadow(i_PositionWS.xz, weight0, shadow);
}
#endif
#if d_Crest_SimpleTransparency || d_Crest_FoamBioluminescence
#if !d_Crest_SimpleTransparency
if (_Crest_FoamEnabled && _Crest_FoamBioluminescenceEnabled)
#endif
{
Cascade::MakeDepth(slice0).SampleSignedDepthFromSeaLevelAndDistance(i_PositionWS.xz, weight0, waterDepth, shorelineDistance);
}
#endif
}
if (weight1 > m_CrestSampleLodThreshold)
{
Cascade::MakeAnimatedWaves(slice1).SampleNormals(i_UndisplacedXZ, weight1, o_NormalWS.xz, _determinant);
if (_Crest_ApplyDisplacementNormals)
{
Cascade::MakeAnimatedWaves(slice1).SampleDisplacementNormal(i_UndisplacedXZ, weight1, o_NormalWS.xz, _determinant);
}
#if d_Crest_CustomMesh && d_Crest_FlowLod
Cascade::MakeFlow(slice1).SampleFlow(i_UndisplacedXZ, weight1, flowData);
#endif
if (_Crest_FoamEnabled)
{
Cascade::MakeFoam(slice1).SampleFoam(i_UndisplacedXZ, weight1, foam);
}
#if d_Crest_AlbedoLod
if (_Crest_AlbedoEnabled)
{
Cascade::MakeAlbedo(slice1).SampleAlbedo(i_UndisplacedXZ, weight1, albedo);
}
#endif
#if d_Crest_ShadowLod
if (_Crest_ShadowsEnabled)
{
Cascade::MakeShadow(slice1).SampleShadow(i_PositionWS.xz, weight1, shadow);
}
#endif
#if d_Crest_SimpleTransparency || d_Crest_FoamBioluminescence
#if !d_Crest_SimpleTransparency
if (_Crest_FoamEnabled && _Crest_FoamBioluminescenceEnabled)
#endif
{
Cascade::MakeDepth(slice1).SampleSignedDepthFromSeaLevelAndDistance(i_PositionWS.xz, weight1, waterDepth, shorelineDistance);
}
#endif
}
// Invert so shadows are black as we normally multiply this by lighting.
@@ -191,99 +230,88 @@ void Fragment(m_Properties)
// Data that displays to the edge.
// The default simulation value has been written to the border of the last slice.
half3 absorption = 0.0; half3 scattering = 0.0;
half3 absorption = _Crest_Absorption.xyz; half3 scattering = _Crest_Scattering.xyz;
#if d_Crest_AbsorptionLod || d_Crest_ScatteringLod
{
const float weight0 = (1.0 - (isLastLod ? 0.0 : i_LodAlpha)) * cascade0._Weight;
const float weight1 = (1.0 - weight0) * cascade1._Weight;
#if d_Crest_ScatteringLod
if (g_Crest_SampleScatteringSimulation)
{
scattering = 0.0;
}
#endif
#if d_Crest_AbsorptionLod
if (g_Crest_SampleAbsorptionSimulation)
{
absorption = 0.0;
}
#endif
if (weight0 > m_CrestSampleLodThreshold)
{
#if d_Crest_ScatteringLod
if (g_Crest_SampleScatteringSimulation)
{
Cascade::MakeScattering(slice0).SampleScattering(i_UndisplacedXZ, weight0, scattering);
}
#endif
#if d_Crest_AbsorptionLod
if (g_Crest_SampleAbsorptionSimulation)
{
Cascade::MakeAbsorption(slice0).SampleAbsorption(i_UndisplacedXZ, weight0, absorption);
}
#endif
}
if (weight1 > m_CrestSampleLodThreshold)
{
#if d_Crest_ScatteringLod
if (g_Crest_SampleScatteringSimulation)
{
Cascade::MakeScattering(slice1).SampleScattering(i_UndisplacedXZ, weight1, scattering);
}
#endif
#if d_Crest_AbsorptionLod
if (g_Crest_SampleAbsorptionSimulation)
{
Cascade::MakeAbsorption(slice1).SampleAbsorption(i_UndisplacedXZ, weight1, absorption);
}
#endif
}
}
#endif
if (!g_Crest_SampleScatteringSimulation)
{
scattering = _Crest_Scattering.xyz;
}
if (!g_Crest_SampleAbsorptionSimulation)
{
absorption = _Crest_Absorption.xyz;
}
#if d_Crest_FlowLod
#if !d_Crest_CustomMesh
flowData = i_Flow;
#endif
const Flow flow = Flow::Make(flowData, g_Crest_Flow);
#endif
// Determinant needs to be one when no waves.
if (isLastLod)
{
_determinant += 1.0 - weight0;
waterDepth = 10000.0;
}
// Normal.
{
if (_Crest_NormalMapEnabled)
{
o_NormalWS.xz += SampleNormalMaps
(
#ifdef CREST_FLOW_ON
flow,
#if d_Transparent
// Feather at intersection. Cannot be used for shadows since depth is not available.
const float feather =
#if d_Crest_SimpleTransparency
saturate(waterDepth / 0.2);
#else
saturate((sceneZ - pixelZ) / 0.2);
#endif
#endif
_Crest_NormalMapTiledTexture,
_Crest_NormalMapStrength,
i_UndisplacedXZ,
i_LodAlpha,
cascade0
);
}
o_NormalWS = normalize(o_NormalWS);
WaterNormal
(
i_WaterLevelDerivatives,
i_ViewDirectionWS,
_Crest_MinimumReflectionDirectionY,
underwater,
o_NormalWS
);
o_NormalWS = normalize(o_NormalWS);
o_NormalWS.xz *= _Crest_NormalsStrengthOverall;
o_NormalWS.y = lerp(1.0, o_NormalWS.y, _Crest_NormalsStrengthOverall);
if (underwater)
{
// Flip when underwater.
o_NormalWS.xyz *= -1.0;
}
}
// Default for opaque render type.
float sceneDistance = 1000.0;
float3 scenePositionWS = 0.0;
const half3 ambientLight = AmbientLight();
const half3 extinction = VolumeExtinction(absorption, scattering);
float3 lightIntensity = 0.0;
half3 lightDirection = 0.0;
@@ -295,24 +323,110 @@ void Fragment(m_Properties)
lightDirection
);
half3 additionalLight = AdditionalLighting(i_PositionWS, i_ScreenPositionRaw, i_StaticLightMapUV);
// Normal.
{
#if d_Crest_NormalMap
if (_Crest_NormalMapEnabled)
{
const half2 normalMap = SampleNormalMaps
(
#if d_Crest_FlowLod
flow,
#endif
_Crest_NormalMapTiledTexture,
_Crest_NormalMapStrength,
i_UndisplacedXZ,
i_LodAlpha,
cascade0
);
half normalMapStrength = _Crest_NormalMapStrength;
if (_Crest_NormalMapTurbulenceEnabled)
{
normalMapStrength = NormalMapTurbulence
(
o_NormalWS,
normalMap,
normalMapStrength,
_Crest_NormalMapTurbulenceCoverage,
_Crest_NormalMapTurbulenceStrength,
i_ViewDirectionWS,
_determinant,
g_Crest_WaterCenter.y + i_WaterLevelOffset,
pixelZ,
lightDirection
);
}
o_NormalWS.xz += normalMap * normalMapStrength;
}
#endif // d_Crest_NormalMap
// Handles normalization.
WaterNormal
(
_Crest_NormalsStrengthOverall,
i_Underwater,
o_NormalWS
);
}
const half3 ambientLight = AmbientLight();
half3 additionalLight = 0.0;
#if d_Crest_AdditionalLights
additionalLight = AdditionalLighting(i_PositionWS, i_ScreenPositionRaw, i_StaticLightMapUV, i_PositionSS, o_NormalWS);
#endif
#if CREST_BIRP
#ifndef USING_DIRECTIONAL_LIGHT
// BIRP additional lights are the main light.
lightIntensity *= max(k_Crest_AdditionalLightLerp, dot(o_NormalWS, lightDirection));
#endif
#endif
// Default for opaque render type.
float sceneDistance = 1000.0;
float3 scenePositionWS = i_PositionWS;
#if d_Crest_SimpleTransparency
sceneDistance = waterDepth;
// Increase ray for grazing angles.
sceneDistance += (1.0 - dot(i_ViewDirectionWS, o_NormalWS)) * waterDepth;
scenePositionWS.y = i_PositionWS.y - waterDepth;
// Cannot sample scene so go with average light.
o_Emission = i_Underwater ? 0.0 : (0.5 * (lightIntensity + additionalLight + ambientLight) * INV_PI);
#if CREST_HDRP
o_Emission /= GetCurrentExposureMultiplier();
#endif
#endif
bool caustics = !i_Underwater;
#if !d_Crest_SimpleTransparency
#if d_Transparent
#ifndef d_SkipRefraction
bool caustics;
RefractedScene
(
_Crest_RefractionStrength,
1.000293, // air
_Crest_RefractiveIndexOfWater,
o_NormalWS,
i_PositionWS,
i_ScreenPosition.xy,
i_ScreenPositionRaw,
pixelZ,
i_SceneColor,
i_ViewDirectionWS,
sceneZ,
sceneRawZ,
underwater,
i_SceneZRaw,
cascade0._Scale,
i_LodAlpha,
i_Underwater,
_Crest_TotalInternalReflectionIntensity,
o_Emission,
sceneDistance,
scenePositionWS,
scenePositionSS,
caustics
);
@@ -329,45 +443,48 @@ void Fragment(m_Properties)
#endif
#endif // d_SkipRefraction
#endif // d_Transparent
#endif // d_Crest_SimpleTransparency
float refractedSeaLevel = g_Crest_WaterCenter.y;
float3 refractedSurfacePosition = float3(0, refractedSeaLevel, 0);
if (!underwater && slice1 < g_Crest_LodCount)
{
// Sample larger slice to avoid the first slice.
float4 displacement = Cascade::MakeAnimatedWaves(slice1).Sample(scenePositionWS.xz);
refractedSeaLevel = g_Crest_WaterCenter.y + displacement.w;
refractedSurfacePosition = displacement.xyz;
refractedSurfacePosition.y += refractedSeaLevel;
}
#if d_Crest_OutScattering
// Out-scattering.
if (!underwater)
if (!i_Underwater)
{
// Account for average extinction of light as it travels down through volume. Assume flat water as anything else would be expensive.
half3 extinction = absorption.xyz + scattering.xyz;
o_Emission *= exp(-extinction * max(0.0, refractedSeaLevel - scenePositionWS.y));
// Account for extinction of light as it travels down through volume.
o_Emission *= exp(-extinction * max(0.0, i_PositionWS.y - scenePositionWS.y));
}
#endif
#if d_Transparent
#ifndef d_SkipRefraction
// Caustics
if (_Crest_CausticsEnabled && !underwater && caustics)
if (_Crest_CausticsEnabled && !i_Underwater && caustics)
{
half lightOcclusion = PrimaryLightShadows(scenePositionWS, positionSS);
half lightOcclusion = 1.0;
#if !d_Crest_SimpleTransparency
lightOcclusion = PrimaryLightShadows(scenePositionWS, scenePositionSS);
#endif
#if d_Crest_SimpleTransparency
if (_Crest_RefractionStrength > 0.0)
{
// Gives a parallax like effect.
const half3 ray = refract(-i_ViewDirectionWS, o_NormalWS, 1.0 / _Crest_RefractiveIndexOfWater) * _Crest_RefractionStrength;
scenePositionWS += ray * waterDepth * 2.0;
}
#endif
half blur = 0.0;
#ifdef CREST_FLOW_ON
#if d_Crest_FlowLod
blur = _Crest_CausticsMotionBlur;
#endif
o_Emission *= Caustics
(
#ifdef CREST_FLOW_ON
#if d_Crest_FlowLod
flow,
#endif
scenePositionWS,
refractedSurfacePosition.y,
i_PositionWS.y,
lightIntensity,
lightDirection,
lightOcclusion,
@@ -380,7 +497,7 @@ void Fragment(m_Properties)
_Crest_CausticsDistortionTiledTexture,
_Crest_CausticsDistortionStrength,
blur,
underwater
_Crest_CausticsForceDistortion
);
}
#endif // d_SkipRefraction
@@ -404,7 +521,6 @@ void Fragment(m_Properties)
}
// Volume Lighting
const half3 extinction = VolumeExtinction(absorption, scattering);
const half3 volumeOpacity = VolumeOpacity(extinction, sceneDistance);
const half3 volumeLight = VolumeLighting
(
@@ -417,8 +533,10 @@ void Fragment(m_Properties)
lightDirection,
lightIntensity,
additionalLight,
_Crest_AdditionalLightsBlend,
_Crest_AmbientTerm,
_Crest_DirectTerm,
_Crest_DirectTermAdditional,
sss,
_Crest_ShadowsAffectsAmbientFactor
);
@@ -431,15 +549,16 @@ void Fragment(m_Properties)
(
i_ViewDirectionWS,
o_NormalWS,
underwater,
i_Underwater,
1.0, // air
_Crest_RefractiveIndexOfWater,
_Crest_TotalInternalReflectionIntensity,
_Crest_Fresnel,
transmitted,
reflected
);
if (underwater)
if (i_Underwater)
{
o_Emission *= transmitted;
o_Emission += volumeLight * reflected;
@@ -448,14 +567,20 @@ void Fragment(m_Properties)
{
o_Emission *= 1.0 - volumeOpacity;
o_Emission += volumeLight * volumeOpacity;
o_Emission *= transmitted;
if (_Crest_ApplyFresnelToVolumeLighting)
{
o_Emission *= transmitted;
}
}
}
#if _SPECULAR_SETUP
// Specular
{
o_Specular = _Crest_Specular * reflected * shadow.y;
}
#endif
// Smoothness
{
@@ -465,24 +590,26 @@ void Fragment(m_Properties)
// Occlusion
{
o_Occlusion = underwater ? _Crest_OcclusionUnderwater : _Crest_Occlusion;
o_Occlusion = i_Underwater ? _Crest_OcclusionUnderwater : _Crest_Occlusion;
}
// Planar Reflections
#if d_Crest_PlanarReflections
if (_Crest_PlanarReflectionsEnabled)
{
half4 reflection = PlanarReflection
(
_Crest_ReflectionTexture,
sampler_Crest_ReflectionTexture,
_Crest_ReflectionColorTexture,
sampler_Crest_ReflectionColorTexture,
_Crest_PlanarReflectionsIntensity,
o_Smoothness,
_Crest_PlanarReflectionsRoughness,
pixelZ,
o_NormalWS,
_Crest_PlanarReflectionsDistortion,
i_ViewDirectionWS,
i_ScreenPosition.xy,
underwater
i_Underwater
);
half alpha = reflection.a;
@@ -491,13 +618,14 @@ void Fragment(m_Properties)
// Results are darker than Unity's.
o_Occlusion *= 1.0 - alpha;
}
#endif // d_Crest_PlanarReflections
// Foam
if (_Crest_FoamEnabled)
{
half albedo = MultiScaleFoamAlbedo
half2 albedo = MultiScaleFoamAlbedo
(
#ifdef CREST_FLOW_ON
#if d_Crest_FlowLod
flow,
#endif
_Crest_FoamTiledTexture,
@@ -506,23 +634,24 @@ void Fragment(m_Properties)
cascade0,
cascade1,
i_LodAlpha,
i_UndisplacedXZ
);
half2 normal = MultiScaleFoamNormal
(
#ifdef CREST_FLOW_ON
flow,
#endif
_Crest_FoamTiledTexture,
_Crest_FoamFeather,
_Crest_FoamNormalStrength,
foam,
albedo,
cascade0,
cascade1,
i_LodAlpha,
i_UndisplacedXZ,
_Crest_FoamBioluminescenceEnabled && _Crest_FoamBioluminescenceSparklesEnabled
);
half2 normal = MultiScaleFoamNormal
(
#if d_Crest_FlowLod
flow,
#endif
_Crest_FoamTiledTexture,
_Crest_FoamFeather,
foam,
cascade0,
cascade1,
i_LodAlpha,
i_UndisplacedXZ,
_Crest_FoamNormalStrength,
albedo.x,
pixelZ
);
@@ -530,13 +659,13 @@ void Fragment(m_Properties)
ApplyFoamToSurface
(
albedo,
albedo.x,
normal,
intensity,
_Crest_Occlusion,
_Crest_FoamSmoothness,
_Crest_Specular,
underwater,
i_Underwater,
o_Albedo,
o_NormalWS,
o_Emission,
@@ -546,92 +675,205 @@ void Fragment(m_Properties)
);
// We will use this for shadow casting.
foam = albedo;
const half foamData = foam;
foam = albedo.r;
#if d_Crest_FoamBioluminescence
if (_Crest_FoamBioluminescenceEnabled)
{
half3 emission = FoamBioluminescence
(
foamData,
albedo.r,
_Crest_FoamBioluminescenceColor.rgb,
_Crest_FoamBioluminescenceIntensity,
_Crest_FoamBioluminescenceGlowCoverage,
_Crest_FoamBioluminescenceGlowIntensity,
_Crest_FoamBioluminescenceSparklesEnabled,
albedo.y,
_Crest_FoamBioluminescenceSparklesCoverage,
_Crest_FoamBioluminescenceSparklesIntensity,
_Crest_FoamBioluminescenceMaximumDepth,
waterDepth
);
emission *= _Crest_FoamBioluminescenceSeaLevelOnly ? saturate(1.0 - abs(i_WaterLevelOffset)) : 1.0;
#if d_Transparent
// Apply feathering to avoid hardening the edge.
emission *= feather * feather * feather;
#endif
o_Emission += emission;
}
#endif // d_Crest_FoamBioluminescence
}
// Albedo
#if d_Crest_AlbedoLod
if (_Crest_AlbedoEnabled)
{
const float foamMask = _Crest_AlbedoIgnoreFoam ? (1.0 - saturate(foam)) : 1.0;
o_Albedo = lerp(o_Albedo, albedo.rgb, albedo.a * foamMask);
o_Emission *= 1.0 - albedo.a * foamMask;
}
#endif
#if d_Crest_SimpleTransparency
o_Alpha = i_Underwater
? 1.0 - transmitted
: max(max(length(volumeOpacity), _Crest_TransparencyMinimumAlpha), max(foam, albedo.a));
#endif
// Alpha
{
#ifndef CREST_SHADOWPASS
#if d_Transparent
// Feather at intersection. Cannot be used for shadows since depth is not available.
o_Alpha = saturate((sceneZ - pixelZ) / 0.2);
o_Alpha = min(o_Alpha, feather);
#endif
#endif
// This keyword works for all RPs despite BIRP having prefixes in serialised data.
#if _ALPHATEST_ON
#if d_Crest_AlphaTest
#if CREST_SHADOWPASS
o_Alpha = max(foam, albedo.a) - _Crest_ShadowCasterThreshold;
o_Alpha = min(o_Alpha, max(foam, albedo.a) - _Crest_ShadowCasterThreshold);
#endif
// Add 0.5 bias for LOD blending and texel resolution correction. This will help to
// tighten and smooth clipped edges.
o_Alpha -= ClipSurface(i_PositionWS.xz) > 0.5 ? 2.0 : 0.0;
#endif // _ALPHATEST_ON
#endif // d_Crest_AlphaTest
// Specular in HDRP is still affected outside the 0-1 alpha range.
o_Alpha = min(o_Alpha, 1.0);
}
if (!i_Underwater && _Crest_MinimumReflectionDirectionY > -1.0)
{
o_NormalWS = ApplyMinimumReflectionDirectionY(_Crest_MinimumReflectionDirectionY, i_ViewDirectionWS, o_NormalWS);
}
SetUpFog
(
underwater,
i_Underwater,
i_PositionWS,
1.0, // N/A: multiplier for fog nodes
sceneDistance - negativeFog,
pixelZ - i_NegativeFog,
i_ViewDirectionWS,
positionSS
i_PositionSS
);
}
#if d_Crest_CustomMesh
// Handles the last slice logic differently to match the mesh.
// Clip surface for quad will not match chunks mesh at last LOD as collateral.
#define PositionToSliceIndices MeshPositionToSliceIndices
#endif
// IMPORTANT!
// Do not branch on o_Alpha, as it is not robust. Rendering will break on stereo
// rendering in the form of losing additional lighting and/or broken reflection
// probe sampling. This is an issue with the shader compiler it seems.
void Fragment(m_Properties(inout))
{
const float2 positionSS = i_ScreenPosition.xy * _ScreenSize.xy;
bool underwater = IsUnderWater(i_Facing, g_Crest_ForceUnderwater, positionSS);
float sceneRawZ = i_SceneDepthRaw;
float negativeFog = _ProjectionParams.y;
#if d_Crest_AlphaTest
#if !d_Crest_SimpleTransparency
#ifndef CREST_SHADOWPASS
#if (CREST_PORTALS != 0)
if (m_CrestPortal)
{
const float pixelRawZ = i_ScreenPositionRaw.z / i_ScreenPositionRaw.w;
o_Alpha = Portal::EvaluateSurface(i_ScreenPosition.xy, pixelRawZ, i_PositionWS, underwater, sceneRawZ, negativeFog) ? -1.0 : 1.0;
#ifndef SHADER_API_WEBGPU
clip(o_Alpha);
#endif
}
#endif
#endif
#endif
#endif
uint slice0;
uint slice1;
float alpha;
#if d_Crest_AlphaTest || d_Crest_CustomMesh
PositionToSliceIndices(i_PositionWS.xz, 0, g_Crest_LodCount - 1, g_Crest_WaterScale, slice0, slice1, alpha);
#endif
#if d_Crest_AlphaTest
{
const Cascade cascade0 = Cascade::Make(slice0);
const Cascade cascade1 = Cascade::Make(slice1);
const float weight0 = (1.0 - alpha) * cascade0._Weight;
const float weight1 = (1.0 - weight0) * cascade1._Weight;
float clipSurface = 0.0;
if (weight0 > m_CrestSampleLodThreshold)
{
Cascade::MakeClip(slice0).SampleClip(i_PositionWS.xz, weight0, clipSurface);
}
if (weight1 > m_CrestSampleLodThreshold)
{
Cascade::MakeClip(slice1).SampleClip(i_PositionWS.xz, weight1, clipSurface);
}
// Add 0.5 bias for LOD blending and texel resolution correction. This will help to
// tighten and smooth clipped edges.
o_Alpha -= clipSurface > 0.5 ? 2.0 : 0.0;
#ifndef SHADER_API_WEBGPU
clip(o_Alpha);
#endif
}
#endif
{
#if !d_Crest_CustomMesh
slice0 = _Crest_LodIndex;
slice1 = _Crest_LodIndex + 1;
alpha = i_LodAlpha;
#endif
i_LodAlpha = alpha;
Fragment
(
m_Parameters,
slice0,
slice1,
positionSS,
underwater,
sceneRawZ,
negativeFog
);
}
}
#ifdef PosToSliceIndices
#undef PosToSliceIndices
#endif
m_CrestNameSpaceEnd
#endif // SHADERGRAPH_PREVIEW
void Fragment_float(m_Properties)
void Fragment_float(m_Properties(out))
{
#if SHADERGRAPH_PREVIEW
o_Albedo = 0.0;
o_NormalWS = half3(0.0, 1.0, 0.0);
o_NormalWS = i_NormalWS;
o_Specular = 0.0;
o_Emission = 0.0;
o_Smoothness = 0.7;
o_Smoothness = 0.9;
o_Occlusion = 1.0;
o_Alpha = 1.0;
#else // SHADERGRAPH_PREVIEW
m_Crest::Fragment
(
i_UndisplacedXZ,
i_LodAlpha,
i_WaterLevelOffset,
i_WaterLevelDerivatives,
i_Flow,
i_ViewDirectionWS,
i_Facing,
i_SceneColor,
i_SceneDepthRaw,
i_ScreenPosition,
i_ScreenPositionRaw,
i_PositionWS,
i_PositionVS,
i_StaticLightMapUV,
o_Albedo,
o_NormalWS,
o_Specular,
o_Emission,
o_Smoothness,
o_Occlusion,
o_Alpha
);
#endif // SHADERGRAPH_PREVIEW
#if !SHADERGRAPH_PREVIEW
m_Crest::Fragment(m_Parameters);
#endif
}
#undef m_Properties

View File

@@ -8,14 +8,14 @@
m_CrestNameSpace
float CalculateFresnelReflectionCoefficient(const float i_CosineTheta, const float i_RefractiveIndexOfAir, const float i_RefractiveIndexOfWater)
float CalculateFresnelReflectionCoefficient(const float i_CosineTheta, const float i_RefractiveIndexOfAir, const float i_RefractiveIndexOfWater, const float i_Fresnel)
{
// Fresnel calculated using Schlick's approximation.
// See: http://www.cs.virginia.edu/~jdl/bib/appearance/analytic%20models/schlick94b.pdf
// Reflectance at facing angle.
float R_0 = (i_RefractiveIndexOfAir - i_RefractiveIndexOfWater) / (i_RefractiveIndexOfAir + i_RefractiveIndexOfWater);
R_0 *= R_0;
const float R_theta = R_0 + (1.0 - R_0) * pow(max(0., 1.0 - i_CosineTheta), 5.0);
const float R_theta = R_0 + (1.0 - R_0) * pow(max(0., 1.0 - i_CosineTheta), i_Fresnel);
return R_theta;
}
@@ -24,6 +24,7 @@ void ApplyReflectionUnderwater(
const half3 i_NormalWS,
const float i_RefractiveIndexOfAir,
const float i_RefractiveIndexOfWater,
const float i_Fresnel,
out float o_LightTransmitted,
out float o_LightReflected
) {
@@ -35,7 +36,7 @@ void ApplyReflectionUnderwater(
// Have to calculate the incident angle of incoming light to water.
// Surface based on how it would be refracted so as to hit the camera.
const float cosIncomingAngle = cos(asin(clamp((i_RefractiveIndexOfWater * sin(acos(cosOutgoingAngle))) / i_RefractiveIndexOfAir, -1.0, 1.0)));
const float reflectionCoefficient = CalculateFresnelReflectionCoefficient(cosIncomingAngle, i_RefractiveIndexOfAir, i_RefractiveIndexOfWater);
const float reflectionCoefficient = CalculateFresnelReflectionCoefficient(cosIncomingAngle, i_RefractiveIndexOfAir, i_RefractiveIndexOfWater, i_Fresnel);
o_LightTransmitted = (1.0 - reflectionCoefficient);
o_LightTransmitted = max(o_LightTransmitted, 0.0);
}
@@ -44,7 +45,7 @@ void ApplyReflectionUnderwater(
{
// Angle of incident is angle of reflection.
const float cosIncomingAngle = cosOutgoingAngle;
const float reflectionCoefficient = CalculateFresnelReflectionCoefficient(cosIncomingAngle, i_RefractiveIndexOfAir, i_RefractiveIndexOfWater);
const float reflectionCoefficient = CalculateFresnelReflectionCoefficient(cosIncomingAngle, i_RefractiveIndexOfAir, i_RefractiveIndexOfWater, i_Fresnel);
o_LightReflected = reflectionCoefficient;
}
}
@@ -57,15 +58,14 @@ void ApplyFresnel
const float i_RefractiveIndexOfAir,
const float i_RefractiveIndexOfWater,
const float i_TirIntensity,
const float i_Fresnel,
out float o_LightTransmitted,
out float o_LightReflected
)
{
o_LightTransmitted = 1.0;
if (i_IsUnderwater)
{
ApplyReflectionUnderwater(i_ViewDirectionWS, i_NormalWS, i_RefractiveIndexOfAir, i_RefractiveIndexOfWater, o_LightTransmitted, o_LightReflected);
ApplyReflectionUnderwater(i_ViewDirectionWS, i_NormalWS, i_RefractiveIndexOfAir, i_RefractiveIndexOfWater, i_Fresnel, o_LightTransmitted, o_LightReflected);
// Limit how strong TIR is. Not sure if this is the best way but it seems to work gracefully.
o_LightTransmitted = max(o_LightTransmitted, 1.0 - i_TirIntensity);
o_LightReflected = min(o_LightReflected, i_TirIntensity);
@@ -74,7 +74,8 @@ void ApplyFresnel
{
const float cosAngle = max(dot(i_NormalWS, i_ViewDirectionWS), 0.0);
// Hardcode water IOR for above surface.
o_LightReflected = CalculateFresnelReflectionCoefficient(cosAngle, i_RefractiveIndexOfAir, 1.33);
o_LightReflected = CalculateFresnelReflectionCoefficient(cosAngle, i_RefractiveIndexOfAir, 1.33, i_Fresnel);
o_LightTransmitted = 1.0 - o_LightReflected;
}
}

View File

@@ -11,9 +11,7 @@
// These are per cascade, set per chunk instance.
CBUFFER_START(CrestChunkGeometryData)
float _Crest_ChunkMeshScaleAlpha;
float _Crest_ChunkMeshScaleAlphaSource;
float _Crest_ChunkGeometryGridWidth;
float _Crest_ChunkGeometryGridWidthSource;
CBUFFER_END
m_CrestNameSpace
@@ -93,6 +91,22 @@ void SnapAndTransitionVertLayout(in const float i_meshScaleAlpha, in const Casca
SnapAndTransitionVertLayout(UNITY_MATRIX_M, i_meshScaleAlpha, i_cascadeData0, i_geometryGridSize, io_worldPos, o_lodAlpha);
}
// Fix precision errors at edges.
void PatchVerticeLayout(const float2 i_ObjectPosition, const float2 i_CameraPosition, inout float2 io_PositionWS)
{
// Scale up by small "epsilon" to solve numerical issues. Expand slightly about tile center.
// :WaterGridPrecisionErrors
const float2 center = i_ObjectPosition;
const float2 camera = abs(i_CameraPosition);
// Scale "epsilon" by distance from zero. Gaps look bad from above surface, and
// overlaps look bad from below surface. We want to close gaps without introducing
// overlaps. A fixed "epsilon" will either not solve gaps at large distances or
// introduce too many overlaps at small distances. Even with scaling, there are
// still unsolvable overlaps underwater (especially at large distances). 100,000
// (0.00001) is the maximum position before Unity warns the user of precision issues.
io_PositionWS = lerp(center, io_PositionWS, lerp(1.0, 1.01, max(camera.x, camera.y) * 0.00001));
}
m_CrestNameSpaceEnd
#endif // CREST_WATER_VERT_HELPERS_H

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c23f497aedede4290815c65dbfb8c41e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 092e2d3b5cf2b4befb63be63e99ea668
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,997 @@
{
"m_SGVersion": 3,
"m_Type": "UnityEditor.ShaderGraph.GraphData",
"m_ObjectId": "dc52d11acc8d40b988b7e8c972022334",
"m_Properties": [
{
"m_Id": "7e9059fbe5bd45138f2798978fec8e1b"
},
{
"m_Id": "d6811a4a90da4a1d90dd116b1166e9a7"
},
{
"m_Id": "a504c5e2669b46a0806878bfc4e5fe6e"
},
{
"m_Id": "657822dfe20e4bd7bbbc6c91b2559f83"
},
{
"m_Id": "3aae6ac983e147359b4cad3288a29ddb"
},
{
"m_Id": "9af11505f365474aa6e944c99d98ce7d"
},
{
"m_Id": "79c65b5b5cd84bb0a37a4a4194cb788b"
}
],
"m_Keywords": [],
"m_Dropdowns": [],
"m_CategoryData": [
{
"m_Id": "69e164e167b84918b199406f9b8e6e73"
}
],
"m_Nodes": [
{
"m_Id": "306ab5d97971411ead8ce1393f42a506"
},
{
"m_Id": "dccd939768524dfca8b5ae9341b86c38"
},
{
"m_Id": "fda07576d7f341dc91fe8387cfa3c734"
},
{
"m_Id": "aee239246fb14f14a6d36e34c4c9409f"
},
{
"m_Id": "79217e2ae0ce456e95d9d7b3753b66b9"
},
{
"m_Id": "d3ea3be5f6c346cd99299ee3715a57f9"
},
{
"m_Id": "117ce02e4acf4112916c65582270c166"
},
{
"m_Id": "74a7acf692b54b4c8635c91fe0731654"
}
],
"m_GroupDatas": [],
"m_StickyNoteDatas": [],
"m_Edges": [
{
"m_OutputSlot": {
"m_Node": {
"m_Id": "117ce02e4acf4112916c65582270c166"
},
"m_SlotId": 0
},
"m_InputSlot": {
"m_Node": {
"m_Id": "306ab5d97971411ead8ce1393f42a506"
},
"m_SlotId": 6
}
},
{
"m_OutputSlot": {
"m_Node": {
"m_Id": "74a7acf692b54b4c8635c91fe0731654"
},
"m_SlotId": 0
},
"m_InputSlot": {
"m_Node": {
"m_Id": "306ab5d97971411ead8ce1393f42a506"
},
"m_SlotId": 7
}
},
{
"m_OutputSlot": {
"m_Node": {
"m_Id": "79217e2ae0ce456e95d9d7b3753b66b9"
},
"m_SlotId": 0
},
"m_InputSlot": {
"m_Node": {
"m_Id": "306ab5d97971411ead8ce1393f42a506"
},
"m_SlotId": 4
}
},
{
"m_OutputSlot": {
"m_Node": {
"m_Id": "aee239246fb14f14a6d36e34c4c9409f"
},
"m_SlotId": 0
},
"m_InputSlot": {
"m_Node": {
"m_Id": "306ab5d97971411ead8ce1393f42a506"
},
"m_SlotId": 3
}
},
{
"m_OutputSlot": {
"m_Node": {
"m_Id": "d3ea3be5f6c346cd99299ee3715a57f9"
},
"m_SlotId": 0
},
"m_InputSlot": {
"m_Node": {
"m_Id": "306ab5d97971411ead8ce1393f42a506"
},
"m_SlotId": 5
}
},
{
"m_OutputSlot": {
"m_Node": {
"m_Id": "dccd939768524dfca8b5ae9341b86c38"
},
"m_SlotId": 0
},
"m_InputSlot": {
"m_Node": {
"m_Id": "306ab5d97971411ead8ce1393f42a506"
},
"m_SlotId": 1
}
},
{
"m_OutputSlot": {
"m_Node": {
"m_Id": "fda07576d7f341dc91fe8387cfa3c734"
},
"m_SlotId": 0
},
"m_InputSlot": {
"m_Node": {
"m_Id": "306ab5d97971411ead8ce1393f42a506"
},
"m_SlotId": 2
}
}
],
"m_VertexContext": {
"m_Position": {
"x": 0.0,
"y": 0.0
},
"m_Blocks": []
},
"m_FragmentContext": {
"m_Position": {
"x": 0.0,
"y": 0.0
},
"m_Blocks": []
},
"m_PreviewData": {
"serializedMesh": {
"m_SerializedMesh": "{\"mesh\":{\"instanceID\":0}}",
"m_Guid": ""
},
"preventRotation": false
},
"m_Path": "Crest/Surface/Fragment",
"m_GraphPrecision": 1,
"m_PreviewMode": 2,
"m_OutputNode": {
"m_Id": "306ab5d97971411ead8ce1393f42a506"
},
"m_SubDatas": [],
"m_ActiveTargets": []
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.PropertyNode",
"m_ObjectId": "117ce02e4acf4112916c65582270c166",
"m_Group": {
"m_Id": ""
},
"m_Name": "Property",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": -164.0,
"y": 179.5,
"width": 126.5,
"height": 34.0
}
},
"m_Slots": [
{
"m_Id": "914b44103326464e8b55a8d65c402de4"
}
],
"synonyms": [],
"m_Precision": 0,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 0,
"m_CustomColors": {
"m_SerializableColors": []
},
"m_Property": {
"m_Id": "9af11505f365474aa6e944c99d98ce7d"
}
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector3MaterialSlot",
"m_ObjectId": "1aeebfec5a8a4655b6a85cc4aff7a1dc",
"m_Id": 3,
"m_DisplayName": "Specular",
"m_SlotType": 0,
"m_Hidden": false,
"m_ShaderOutputName": "Specular",
"m_StageCapability": 3,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_DefaultValue": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_Labels": []
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector3MaterialSlot",
"m_ObjectId": "259210c0e86a4a4e9a9b189da396d21a",
"m_Id": 1,
"m_DisplayName": "Color",
"m_SlotType": 0,
"m_Hidden": false,
"m_ShaderOutputName": "Color",
"m_StageCapability": 3,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_DefaultValue": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_Labels": []
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector3MaterialSlot",
"m_ObjectId": "2b75f1714337440c8ce94bce183a9e55",
"m_Id": 0,
"m_DisplayName": "Color",
"m_SlotType": 1,
"m_Hidden": false,
"m_ShaderOutputName": "Out",
"m_StageCapability": 3,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_DefaultValue": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_Labels": []
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.SubGraphOutputNode",
"m_ObjectId": "306ab5d97971411ead8ce1393f42a506",
"m_Group": {
"m_Id": ""
},
"m_Name": "Output",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": 0.0,
"y": 0.0,
"width": 0.0,
"height": 0.0
}
},
"m_Slots": [
{
"m_Id": "259210c0e86a4a4e9a9b189da396d21a"
},
{
"m_Id": "6b3889ded68f4399b05b25ed7b2079f4"
},
{
"m_Id": "1aeebfec5a8a4655b6a85cc4aff7a1dc"
},
{
"m_Id": "cd595cbfa4314f1392f1cb929b93947e"
},
{
"m_Id": "e75d6aef43794a5fa61bb21fcec7ef9f"
},
{
"m_Id": "fe004333f6074821afe4321924775fbb"
},
{
"m_Id": "d1b1ec100cfd4b0a8959c2fba3da0112"
}
],
"synonyms": [],
"m_Precision": 0,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 0,
"m_CustomColors": {
"m_SerializableColors": []
},
"IsFirstSlotValid": true
}
{
"m_SGVersion": 1,
"m_Type": "UnityEditor.ShaderGraph.Internal.Vector1ShaderProperty",
"m_ObjectId": "3aae6ac983e147359b4cad3288a29ddb",
"m_Guid": {
"m_GuidSerialized": "03c28b79-a1da-4276-8d2c-91a977859ad5"
},
"m_Name": "Smoothness",
"m_DefaultRefNameVersion": 1,
"m_RefNameGeneratedByDisplayName": "Smoothness",
"m_DefaultReferenceName": "_Smoothness",
"m_OverrideReferenceName": "",
"m_GeneratePropertyBlock": true,
"m_UseCustomSlotLabel": false,
"m_CustomSlotLabel": "",
"m_DismissedVersion": 0,
"m_Precision": 0,
"overrideHLSLDeclaration": false,
"hlslDeclarationOverride": 0,
"m_Hidden": false,
"m_Value": 0.0,
"m_FloatType": 0,
"m_RangeValues": {
"x": 0.0,
"y": 1.0
}
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot",
"m_ObjectId": "62b398277ad74c2e9c99f796aa93a891",
"m_Id": 0,
"m_DisplayName": "Smoothness",
"m_SlotType": 1,
"m_Hidden": false,
"m_ShaderOutputName": "Out",
"m_StageCapability": 3,
"m_Value": 0.0,
"m_DefaultValue": 0.0,
"m_Labels": []
}
{
"m_SGVersion": 1,
"m_Type": "UnityEditor.ShaderGraph.Internal.Vector3ShaderProperty",
"m_ObjectId": "657822dfe20e4bd7bbbc6c91b2559f83",
"m_Guid": {
"m_GuidSerialized": "c87cbf93-a5b2-4b0e-bd11-61f5452b1b8f"
},
"m_Name": "Emission",
"m_DefaultRefNameVersion": 1,
"m_RefNameGeneratedByDisplayName": "Emission",
"m_DefaultReferenceName": "_Emission",
"m_OverrideReferenceName": "",
"m_GeneratePropertyBlock": true,
"m_UseCustomSlotLabel": false,
"m_CustomSlotLabel": "",
"m_DismissedVersion": 0,
"m_Precision": 0,
"overrideHLSLDeclaration": false,
"hlslDeclarationOverride": 0,
"m_Hidden": false,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0,
"w": 0.0
}
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.CategoryData",
"m_ObjectId": "69e164e167b84918b199406f9b8e6e73",
"m_Name": "",
"m_ChildObjectList": [
{
"m_Id": "7e9059fbe5bd45138f2798978fec8e1b"
},
{
"m_Id": "d6811a4a90da4a1d90dd116b1166e9a7"
},
{
"m_Id": "a504c5e2669b46a0806878bfc4e5fe6e"
},
{
"m_Id": "657822dfe20e4bd7bbbc6c91b2559f83"
},
{
"m_Id": "3aae6ac983e147359b4cad3288a29ddb"
},
{
"m_Id": "9af11505f365474aa6e944c99d98ce7d"
},
{
"m_Id": "79c65b5b5cd84bb0a37a4a4194cb788b"
}
]
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector3MaterialSlot",
"m_ObjectId": "6b3889ded68f4399b05b25ed7b2079f4",
"m_Id": 2,
"m_DisplayName": "Normal",
"m_SlotType": 0,
"m_Hidden": false,
"m_ShaderOutputName": "Normal",
"m_StageCapability": 3,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_DefaultValue": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_Labels": []
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.PropertyNode",
"m_ObjectId": "74a7acf692b54b4c8635c91fe0731654",
"m_Group": {
"m_Id": ""
},
"m_Name": "Property",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": -142.5,
"y": 213.5,
"width": 105.0,
"height": 34.0
}
},
"m_Slots": [
{
"m_Id": "7deef838b6744b40a3bacb0d96991f2f"
}
],
"synonyms": [],
"m_Precision": 0,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 0,
"m_CustomColors": {
"m_SerializableColors": []
},
"m_Property": {
"m_Id": "79c65b5b5cd84bb0a37a4a4194cb788b"
}
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.PropertyNode",
"m_ObjectId": "79217e2ae0ce456e95d9d7b3753b66b9",
"m_Group": {
"m_Id": ""
},
"m_Name": "Property",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": -160.5,
"y": 111.5,
"width": 123.0,
"height": 34.0
}
},
"m_Slots": [
{
"m_Id": "94eddae4a910492b81d2a10f9aa4b3ce"
}
],
"synonyms": [],
"m_Precision": 0,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 0,
"m_CustomColors": {
"m_SerializableColors": []
},
"m_Property": {
"m_Id": "657822dfe20e4bd7bbbc6c91b2559f83"
}
}
{
"m_SGVersion": 1,
"m_Type": "UnityEditor.ShaderGraph.Internal.Vector1ShaderProperty",
"m_ObjectId": "79c65b5b5cd84bb0a37a4a4194cb788b",
"m_Guid": {
"m_GuidSerialized": "3a9dc46c-6bfe-45f8-8b09-e890761dbd17"
},
"m_Name": "Alpha",
"m_DefaultRefNameVersion": 1,
"m_RefNameGeneratedByDisplayName": "Alpha",
"m_DefaultReferenceName": "_Alpha",
"m_OverrideReferenceName": "",
"m_GeneratePropertyBlock": true,
"m_UseCustomSlotLabel": false,
"m_CustomSlotLabel": "",
"m_DismissedVersion": 0,
"m_Precision": 0,
"overrideHLSLDeclaration": false,
"hlslDeclarationOverride": 0,
"m_Hidden": false,
"m_Value": 0.0,
"m_FloatType": 0,
"m_RangeValues": {
"x": 0.0,
"y": 1.0
}
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot",
"m_ObjectId": "7deef838b6744b40a3bacb0d96991f2f",
"m_Id": 0,
"m_DisplayName": "Alpha",
"m_SlotType": 1,
"m_Hidden": false,
"m_ShaderOutputName": "Out",
"m_StageCapability": 3,
"m_Value": 0.0,
"m_DefaultValue": 0.0,
"m_Labels": []
}
{
"m_SGVersion": 1,
"m_Type": "UnityEditor.ShaderGraph.Internal.Vector3ShaderProperty",
"m_ObjectId": "7e9059fbe5bd45138f2798978fec8e1b",
"m_Guid": {
"m_GuidSerialized": "550c25ce-1870-45ea-a63d-ed7249d6bfc3"
},
"m_Name": "Color",
"m_DefaultRefNameVersion": 1,
"m_RefNameGeneratedByDisplayName": "Color",
"m_DefaultReferenceName": "_Color",
"m_OverrideReferenceName": "",
"m_GeneratePropertyBlock": true,
"m_UseCustomSlotLabel": false,
"m_CustomSlotLabel": "",
"m_DismissedVersion": 0,
"m_Precision": 0,
"overrideHLSLDeclaration": false,
"hlslDeclarationOverride": 0,
"m_Hidden": false,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0,
"w": 0.0
}
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector3MaterialSlot",
"m_ObjectId": "8e3e2614b2d844848527e0bf103cda9f",
"m_Id": 0,
"m_DisplayName": "Normal",
"m_SlotType": 1,
"m_Hidden": false,
"m_ShaderOutputName": "Out",
"m_StageCapability": 3,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_DefaultValue": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_Labels": []
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot",
"m_ObjectId": "914b44103326464e8b55a8d65c402de4",
"m_Id": 0,
"m_DisplayName": "Occlusion",
"m_SlotType": 1,
"m_Hidden": false,
"m_ShaderOutputName": "Out",
"m_StageCapability": 3,
"m_Value": 0.0,
"m_DefaultValue": 0.0,
"m_Labels": []
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector3MaterialSlot",
"m_ObjectId": "94eddae4a910492b81d2a10f9aa4b3ce",
"m_Id": 0,
"m_DisplayName": "Emission",
"m_SlotType": 1,
"m_Hidden": false,
"m_ShaderOutputName": "Out",
"m_StageCapability": 3,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_DefaultValue": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_Labels": []
}
{
"m_SGVersion": 1,
"m_Type": "UnityEditor.ShaderGraph.Internal.Vector1ShaderProperty",
"m_ObjectId": "9af11505f365474aa6e944c99d98ce7d",
"m_Guid": {
"m_GuidSerialized": "9b1b639c-8d8a-4493-800e-3b16c796d901"
},
"m_Name": "Occlusion",
"m_DefaultRefNameVersion": 1,
"m_RefNameGeneratedByDisplayName": "Occlusion",
"m_DefaultReferenceName": "_Occlusion",
"m_OverrideReferenceName": "",
"m_GeneratePropertyBlock": true,
"m_UseCustomSlotLabel": false,
"m_CustomSlotLabel": "",
"m_DismissedVersion": 0,
"m_Precision": 0,
"overrideHLSLDeclaration": false,
"hlslDeclarationOverride": 0,
"m_Hidden": false,
"m_Value": 0.0,
"m_FloatType": 0,
"m_RangeValues": {
"x": 0.0,
"y": 1.0
}
}
{
"m_SGVersion": 1,
"m_Type": "UnityEditor.ShaderGraph.Internal.Vector3ShaderProperty",
"m_ObjectId": "a504c5e2669b46a0806878bfc4e5fe6e",
"m_Guid": {
"m_GuidSerialized": "a0454ac6-fe90-4f58-8357-c64bf491ecc8"
},
"m_Name": "Specular",
"m_DefaultRefNameVersion": 1,
"m_RefNameGeneratedByDisplayName": "Specular",
"m_DefaultReferenceName": "_Specular",
"m_OverrideReferenceName": "",
"m_GeneratePropertyBlock": true,
"m_UseCustomSlotLabel": false,
"m_CustomSlotLabel": "",
"m_DismissedVersion": 0,
"m_Precision": 0,
"overrideHLSLDeclaration": false,
"hlslDeclarationOverride": 0,
"m_Hidden": false,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0,
"w": 0.0
}
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.PropertyNode",
"m_ObjectId": "aee239246fb14f14a6d36e34c4c9409f",
"m_Group": {
"m_Id": ""
},
"m_Name": "Property",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": -160.5,
"y": 77.5,
"width": 123.0,
"height": 34.0
}
},
"m_Slots": [
{
"m_Id": "c266950bb3ba42f6afe7ea63308a0ad4"
}
],
"synonyms": [],
"m_Precision": 0,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 0,
"m_CustomColors": {
"m_SerializableColors": []
},
"m_Property": {
"m_Id": "a504c5e2669b46a0806878bfc4e5fe6e"
}
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector3MaterialSlot",
"m_ObjectId": "c266950bb3ba42f6afe7ea63308a0ad4",
"m_Id": 0,
"m_DisplayName": "Specular",
"m_SlotType": 1,
"m_Hidden": false,
"m_ShaderOutputName": "Out",
"m_StageCapability": 3,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_DefaultValue": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_Labels": []
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector3MaterialSlot",
"m_ObjectId": "cd595cbfa4314f1392f1cb929b93947e",
"m_Id": 4,
"m_DisplayName": "Emission",
"m_SlotType": 0,
"m_Hidden": false,
"m_ShaderOutputName": "Emission",
"m_StageCapability": 3,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_DefaultValue": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_Labels": []
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot",
"m_ObjectId": "d1b1ec100cfd4b0a8959c2fba3da0112",
"m_Id": 7,
"m_DisplayName": "Alpha",
"m_SlotType": 0,
"m_Hidden": false,
"m_ShaderOutputName": "Alpha",
"m_StageCapability": 3,
"m_Value": 0.0,
"m_DefaultValue": 0.0,
"m_Labels": []
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.PropertyNode",
"m_ObjectId": "d3ea3be5f6c346cd99299ee3715a57f9",
"m_Group": {
"m_Id": ""
},
"m_Name": "Property",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": -177.5,
"y": 145.5,
"width": 140.0,
"height": 34.0
}
},
"m_Slots": [
{
"m_Id": "62b398277ad74c2e9c99f796aa93a891"
}
],
"synonyms": [],
"m_Precision": 0,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 0,
"m_CustomColors": {
"m_SerializableColors": []
},
"m_Property": {
"m_Id": "3aae6ac983e147359b4cad3288a29ddb"
}
}
{
"m_SGVersion": 1,
"m_Type": "UnityEditor.ShaderGraph.Internal.Vector3ShaderProperty",
"m_ObjectId": "d6811a4a90da4a1d90dd116b1166e9a7",
"m_Guid": {
"m_GuidSerialized": "32196100-75e9-4862-a1f5-ad8a050bcb34"
},
"m_Name": "Normal",
"m_DefaultRefNameVersion": 1,
"m_RefNameGeneratedByDisplayName": "Normal",
"m_DefaultReferenceName": "_Normal",
"m_OverrideReferenceName": "",
"m_GeneratePropertyBlock": true,
"m_UseCustomSlotLabel": false,
"m_CustomSlotLabel": "",
"m_DismissedVersion": 0,
"m_Precision": 0,
"overrideHLSLDeclaration": false,
"hlslDeclarationOverride": 0,
"m_Hidden": false,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0,
"w": 0.0
}
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.PropertyNode",
"m_ObjectId": "dccd939768524dfca8b5ae9341b86c38",
"m_Group": {
"m_Id": ""
},
"m_Name": "Property",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": -142.5,
"y": 9.5,
"width": 105.0,
"height": 34.0
}
},
"m_Slots": [
{
"m_Id": "2b75f1714337440c8ce94bce183a9e55"
}
],
"synonyms": [],
"m_Precision": 0,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 0,
"m_CustomColors": {
"m_SerializableColors": []
},
"m_Property": {
"m_Id": "7e9059fbe5bd45138f2798978fec8e1b"
}
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot",
"m_ObjectId": "e75d6aef43794a5fa61bb21fcec7ef9f",
"m_Id": 5,
"m_DisplayName": "Smoothness",
"m_SlotType": 0,
"m_Hidden": false,
"m_ShaderOutputName": "Smoothness",
"m_StageCapability": 3,
"m_Value": 0.0,
"m_DefaultValue": 0.0,
"m_Labels": []
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.PropertyNode",
"m_ObjectId": "fda07576d7f341dc91fe8387cfa3c734",
"m_Group": {
"m_Id": ""
},
"m_Name": "Property",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": -152.0,
"y": 43.5,
"width": 114.5,
"height": 34.0
}
},
"m_Slots": [
{
"m_Id": "8e3e2614b2d844848527e0bf103cda9f"
}
],
"synonyms": [],
"m_Precision": 0,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 0,
"m_CustomColors": {
"m_SerializableColors": []
},
"m_Property": {
"m_Id": "d6811a4a90da4a1d90dd116b1166e9a7"
}
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot",
"m_ObjectId": "fe004333f6074821afe4321924775fbb",
"m_Id": 6,
"m_DisplayName": "Occlusion",
"m_SlotType": 0,
"m_Hidden": false,
"m_ShaderOutputName": "Occlusion",
"m_StageCapability": 3,
"m_Value": 0.0,
"m_DefaultValue": 0.0,
"m_Labels": []
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: ae86d543ea8a2487e931ca754792c4c0
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 11500000, guid: 60072b568d64c40a485e0fc55012dc9f, type: 3}

View File

@@ -0,0 +1,24 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
#ifndef d_WaveHarmonic_Crest_SurfaceKeywords
#define d_WaveHarmonic_Crest_SurfaceKeywords
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Keywords.hlsl"
#define d_Crest_AlphaTest defined(_ALPHATEST_ON)
#define d_Crest_MotionVectors defined(_TRANSPARENT_WRITES_MOTION_VEC)
#define d_Crest_CustomMesh defined(_CREST_CUSTOM_MESH)
#define d_Crest_AdditionalLights CREST_ADDITIONAL_LIGHTS
#define d_Crest_CausticsForceDistortion CREST_CAUSTICS_FORCE_DISTORTION
#define d_Crest_FoamBioluminescence CREST_FOAM_BIOLUMINESCENCE
#define d_Crest_FoamMultiScale CREST_FOAM_SAMPLING_MULTI_SCALE
#define d_Crest_FoamStochastic CREST_FOAM_SAMPLING_STOCHASTIC
#define d_Crest_NormalMap CREST_NORMAL_MAPS
#define d_Crest_SimpleTransparency CREST_SIMPLE_TRANSPARENCY
#define d_Crest_PlanarReflections CREST_PLANAR_REFLECTIONS
#define d_Crest_PlanarReflectionsApplySmoothness CREST_PLANAR_REFLECTIONS_APPLY_SMOOTHNESS
#endif

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9d4fdd4ba0e96485c93d748132deef6a
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -5,6 +5,7 @@
#define CREST_WATER_NORMAL_H
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Settings.Crest.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Constants.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Macros.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Texture.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Flow.hlsl"
@@ -13,12 +14,43 @@
#include "Packages/com.waveharmonic.crest.shifting-origin/Runtime/Shaders/ShiftingOrigin.hlsl"
#endif
#if _CREST_CUSTOM_MESH
float4 _Crest_NormalMapParameters[MAX_LOD_COUNT];
#define _Crest_ChunkNormalMapParameters _Crest_NormalMapParameters[i_CascadeData._IndexI]
#else
// These are per cascade, set per chunk instance.
float _Crest_ChunkFarNormalsWeight;
float2 _Crest_ChunkNormalScrollSpeed;
#define _Crest_ChunkNormalMapParameters float3(_Crest_ChunkNormalScrollSpeed, _Crest_ChunkFarNormalsWeight)
#endif
m_CrestNameSpace
// Limit how close to horizontal reflection ray can get, useful to avoid unsightly below-horizon reflections.
half3 ApplyMinimumReflectionDirectionY
(
const half i_MinimumReflectionDirectionY,
const half3 i_ViewDirectionWS,
const half3 i_NormalWS
)
{
half3 normal = i_NormalWS;
float3 refl = reflect(-i_ViewDirectionWS, normal);
if (refl.y < i_MinimumReflectionDirectionY)
{
// Find the normal that keeps the reflection direction above the horizon. Compute
// the reflection dir that does work, normalize it, and then normal is half vector
// between this good reflection direction and view direction.
float3 FL = refl;
FL.y = i_MinimumReflectionDirectionY;
FL = normalize(FL);
normal = normalize(FL + i_ViewDirectionWS);
}
return normal;
}
half2 SampleNormalMaps
(
const TiledTexture i_NormalMap,
@@ -35,28 +67,33 @@ half2 SampleNormalMaps
worldXZUndisplaced -= ShiftingOriginOffset(i_NormalMap, i_CascadeData);
#endif
const float3 parameters = _Crest_ChunkNormalMapParameters.xyz;
const float2 speed = parameters.xy;
const float farWeight = parameters.z;
const float2 v0 = float2(0.94, 0.34), v1 = float2(-0.85, -0.53);
float scale = i_NormalMap._scale * i_CascadeData._Scale / 10.0;
const float spdmulL = _Crest_ChunkNormalScrollSpeed.x * i_NormalMap._speed;
float scale = i_NormalMap._scale * i_CascadeData._Scale * 0.1;
const float time = i_NormalMap._speed * g_Crest_Time;
const float spdmulL = speed.x * time;
half2 norm =
UnpackNormal(i_NormalMap.Sample((worldXZUndisplaced + v0 * g_Crest_Time * spdmulL) / scale)).xy +
UnpackNormal(i_NormalMap.Sample((worldXZUndisplaced + v1 * g_Crest_Time * spdmulL) / scale)).xy;
UnpackNormal(i_NormalMap.Sample((worldXZUndisplaced + v0 * spdmulL) / scale)).xy +
UnpackNormal(i_NormalMap.Sample((worldXZUndisplaced + v1 * spdmulL) / scale)).xy;
// blend in next higher scale of normals to obtain continuity
const half nblend = i_LodAlpha * _Crest_ChunkFarNormalsWeight;
const half nblend = i_LodAlpha * farWeight;
if (nblend > 0.001)
{
// next lod level
scale *= 2.0;
const float spdmulH = _Crest_ChunkNormalScrollSpeed.y * i_NormalMap._speed;
const float spdmulH = speed.y * time;
norm = lerp(norm,
UnpackNormal(i_NormalMap.Sample((worldXZUndisplaced + v0 * g_Crest_Time * spdmulH) / scale)).xy +
UnpackNormal(i_NormalMap.Sample((worldXZUndisplaced + v1 * g_Crest_Time * spdmulH) / scale)).xy,
UnpackNormal(i_NormalMap.Sample((worldXZUndisplaced + v0 * spdmulH) / scale)).xy +
UnpackNormal(i_NormalMap.Sample((worldXZUndisplaced + v1 * spdmulH) / scale)).xy,
nblend);
}
// approximate combine of normals. would be better if normals applied in local frame.
return i_Strength * norm;
return norm;
}
half2 SampleNormalMaps
@@ -86,42 +123,66 @@ half2 SampleNormalMaps
) * i_Flow._Weight1;
}
half NormalMapTurbulence
(
const half3 i_NormalWS,
const half2 i_NormalMap,
const half i_NormalMapStrength,
const half i_Coverage,
const half i_Strength,
const half3 i_ViewDirectionWS,
const half i_Determinant,
const half i_WaterLevel,
const float i_PixelZ,
const half3 i_PrimaryLightDirection
)
{
half strength = i_NormalMapStrength;
if (saturate(i_Coverage - i_Determinant) > 0)
{
// Add boosted normal map.
half3 normal = i_NormalWS;
normal.xz += i_NormalMap * i_Strength;
normal = normalize(normal);
// Increase normal map strength only if "sparkle".
if (dot(normal, normalize(i_ViewDirectionWS + i_PrimaryLightDirection)) >= 0.99)
{
// Height (100m) & distance (2m) cull. Looks odd up close and degrades up high.
const half cull = max(saturate(abs(_WorldSpaceCameraPos.y - i_WaterLevel) * 0.01), 1.0 - saturate(i_PixelZ * 0.5));
strength = lerp(i_Strength, strength, cull);
}
}
return strength;
}
void WaterNormal
(
const float2 i_WaterLevelDerivatives,
const half3 i_ViewDirectionWS,
const half i_MinimumReflectionDirectionY,
const half i_Strength,
const bool i_Underwater,
inout half3 io_NormalWS
)
{
// Account for water level changes which change angle of water surface, impacting normal.
io_NormalWS.xz += -i_WaterLevelDerivatives;
// Finalise normal
io_NormalWS = normalize(io_NormalWS);
if (i_Underwater)
if (i_Strength < 1.0)
{
return;
io_NormalWS.xz *= i_Strength;
io_NormalWS.y = lerp(1.0, io_NormalWS.y, i_Strength);
}
// Limit how close to horizontal reflection ray can get, useful to avoid unsightly below-horizon reflections.
if (i_Underwater)
{
float3 refl = reflect(-i_ViewDirectionWS, io_NormalWS);
if (refl.y < i_MinimumReflectionDirectionY)
{
// Find the normal that keeps the reflection direction above the horizon. Compute
// the reflection dir that does work, normalize it, and then normal is half vector
// between this good reflection direction and view direction.
float3 FL = refl;
FL.y = i_MinimumReflectionDirectionY;
FL = normalize(FL);
io_NormalWS = normalize(FL + i_ViewDirectionWS);
}
// Flip when underwater.
io_NormalWS.xyz *= -1.0;
}
}
m_CrestNameSpaceEnd
#endif

View File

@@ -4,12 +4,25 @@
#ifndef CREST_WATER_REFLECTION_H
#define CREST_WATER_REFLECTION_H
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Keywords.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Macros.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Utility.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Utility/Helpers.hlsl"
float _Crest_ReflectionOverscan;
float4 _Crest_ReflectionPositionNormal[2];
Texture2DArray _Crest_ReflectionTexture;
SamplerState sampler_Crest_ReflectionTexture;
float4x4 _Crest_ReflectionMatrixIVP[2];
float4x4 _Crest_ReflectionMatrixV[2];
Texture2DArray _Crest_ReflectionColorTexture;
SamplerState sampler_Crest_ReflectionColorTexture;
Texture2DArray _Crest_ReflectionDepthTexture;
// Try and use already defined samplers.
#if defined(CREST_HDRP) && defined(SHADERCONFIG_CS_HLSL) && defined(UNITY_SHADER_VARIABLES_INCLUDED)
#define sampler_Crest_point_clamp s_point_clamp_sampler
#else
SamplerState sampler_Crest_point_clamp;
#endif
m_CrestNameSpace
@@ -20,6 +33,7 @@ half4 PlanarReflection
const half i_Intensity,
const half i_Smoothness,
const half i_Roughness,
const float i_SurfaceDepth,
const half3 i_NormalWS,
const half i_NormalStrength,
const half3 i_ViewDirectionWS,
@@ -27,6 +41,8 @@ half4 PlanarReflection
const bool i_Underwater
)
{
const uint slice = i_Underwater ? 1 : 0;
half3 planeNormal = half3(0.0, i_Underwater ? -1.0 : 1.0, 0.0);
half3 reflected = reflect(-i_ViewDirectionWS, lerp(planeNormal, i_NormalWS, i_NormalStrength));
reflected.y = -reflected.y;
@@ -38,19 +54,52 @@ half4 PlanarReflection
float2 positionNDC = positionCS.xy * rcp(positionCS.w) * 0.5 + 0.5;
// Overscan.
positionNDC.xy -= 0.5;
positionNDC.xy *= _Crest_ReflectionOverscan;
positionNDC.xy += 0.5;
// Cancel out distortion if out of bounds. We could make this nicer by doing an edge fade but the improvement is
// barely noticeable. Edge fade requires recalculating the above a second time.
const float4 positionAndNormal = _Crest_ReflectionPositionNormal[slice];
if (dot(positionNDC - positionAndNormal.xy, positionAndNormal.zw) < 0.0)
{
float4 positionAndNormal = _Crest_ReflectionPositionNormal[i_Underwater];
if (dot(positionNDC - positionAndNormal.xy, positionAndNormal.zw) < 0.0)
if (i_Underwater)
{
positionNDC = lerp(i_PositionNDC, positionNDC, 0.25);
float2 ndc = i_PositionNDC;
ndc.xy -= 0.5;
ndc.xy *= _Crest_ReflectionOverscan;
ndc.xy += 0.5;
positionNDC = lerp(ndc, positionNDC, 0.25);
}
else
{
// Below horizon sample!
// There are still some bad samples, but they are very minor.
const half2 hypotenuse = positionAndNormal.xy - positionNDC;
const half angle = acos(saturate(dot(positionAndNormal.zw, normalize(hypotenuse))));
const half adjacentLength = (cos(angle) * length(hypotenuse));
positionNDC += (positionAndNormal.zw * adjacentLength) / _Crest_ReflectionOverscan;
}
}
const half roughness = PerceptualSmoothnessToPerceptualRoughness(i_Smoothness);
const half level = PerceptualRoughnessToMipmapLevel(roughness, i_Roughness);
half4 reflection = i_ReflectionsTexture.SampleLevel(sampler_Crest_ReflectionTexture, float3(positionNDC, i_Underwater), level);
half4 reflection;
#if d_Crest_PlanarReflectionsApplySmoothness
if (_Crest_PlanarReflectionsApplySmoothness)
{
const half roughness = PerceptualSmoothnessToPerceptualRoughness(i_Smoothness);
half level = PerceptualRoughnessToMipmapLevel(roughness, i_Roughness);
reflection = i_ReflectionsTexture.SampleLevel(sampler_Crest_ReflectionColorTexture, float3(positionNDC, i_Underwater), level);
}
else
#endif
{
reflection = i_ReflectionsTexture.SampleLevel(sampler_Crest_point_clamp, float3(positionNDC, i_Underwater), 0.0);
}
// If more than four layers are used on the terrain, they will appear black if HDR
// is enabled on the planar reflection camera. Alpha is probably a negative value.
@@ -58,6 +107,21 @@ half4 PlanarReflection
reflection.a *= i_Intensity;
// Mitigate leaks.
{
// TODO: calculate linear depth from device depth directly. First attempt failed.
// Most effective when surface is smooth due to mip-maps. Surprisingly effective
// even when rough.
const float rRawDepth = _Crest_ReflectionDepthTexture.SampleLevel(sampler_Crest_point_clamp, float3(positionNDC, i_Underwater), 0).r;
const float3 rPositionWS = Utility::SafeComputeWorldSpacePosition(positionNDC, rRawDepth, _Crest_ReflectionMatrixIVP[slice]);
const float rDepth = LinearEyeDepth(rPositionWS, _Crest_ReflectionMatrixV[slice]);
if (rRawDepth > 0.0 && rDepth <= i_SurfaceDepth)
{
reflection.a = 0.0;
}
}
return reflection;
}

View File

@@ -4,6 +4,8 @@
#ifndef CREST_WATER_REFRACTION_H
#define CREST_WATER_REFRACTION_H
#if !d_Crest_SimpleTransparency
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Settings.Crest.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Macros.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Utility/Depth.hlsl"
@@ -18,91 +20,144 @@
#define FoveatedRemapLinearToNonUniform(uv) uv
#endif
#if (UNITY_VERSION < 60000000) || !defined(CREST_URP)
float4 _CameraDepthTexture_TexelSize;
#endif
m_CrestNameSpace
float2 GetRefractionCoordinates(const half3 i_View, const half3 i_Normal, const float3 i_Position, const half i_IOR, const half i_Strength)
{
float3 position = i_Position;
#if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0)
position -= _WorldSpaceCameraPos;
#endif
const half3 ray = refract(-i_View, i_Normal, i_IOR) * i_Strength;
float2 uv = ComputeNormalizedDeviceCoordinates(position + ray, UNITY_MATRIX_VP);
#if CREST_HDRP
// Prevent artifacts at edge. Maybe because depth is an atlas for HDRP.
uv = clamp(uv, _CameraDepthTexture_TexelSize.xy, 1.0 - _CameraDepthTexture_TexelSize.xy);
#endif
return FoveatedRemapLinearToNonUniform(uv);
}
// We take the unrefracted scene colour as input because having a Scene Colour node in the graph
// appears to be necessary to ensure the scene colours are bound?
void RefractedScene
(
const half i_RefractionStrength,
const half i_AirIOR,
const half i_WaterIOR,
const half3 i_NormalWS,
const float3 i_PositionWS,
const float2 i_PositionNDC,
const float4 i_ScreenPositionRaw,
const float i_PixelZ,
const half3 i_SceneColorUnrefracted,
const half3 i_View,
const float i_SceneZ,
const float i_SceneZRaw,
const float i_Scale,
const float i_LodAlpha,
const bool i_Underwater,
const half i_TotalInternalReflectionIntensity,
out half3 o_SceneColor,
out float o_SceneDistance,
out float3 o_ScenePositionWS,
out float2 o_PositionSS,
out bool o_Caustics
)
{
float2 positionNDC = i_PositionNDC;
float sceneDepthRaw = i_SceneZRaw;
o_Caustics = true;
// View ray intersects geometry surface either above or below water surface.
float2 refractOffset = i_RefractionStrength * i_NormalWS.xz;
if (!i_Underwater)
half strength = i_RefractionStrength;
const half _AirToWaterRatio = i_AirIOR / i_WaterIOR;
const half _WaterToAirRatio = i_WaterIOR / i_AirIOR;
// If no TIR, then use same IOR.
const bool isA2WR = !i_Underwater || i_TotalInternalReflectionIntensity < 1.0;
const half eta = isA2WR ? _AirToWaterRatio : _WaterToAirRatio;
half3 normal = i_NormalWS;
// Exchanges accuracy for less artifacts.
if (isA2WR)
{
// We're above the water, so behind interface is depth fog.
refractOffset *= min(1.0, 0.5 * (i_SceneZ - i_PixelZ)) / i_SceneZ;
}
else
{
// When looking up through water, full strength ends up being quite intense so reduce it a bunch.
refractOffset *= 0.3;
half multiplier = 0.0;
if (i_Underwater)
{
multiplier = 1.0;
// Max fade when water is 5m deep.
multiplier = saturate(g_Crest_WaterDepthAtViewer * 0.2);
// Max fade by displacement.
multiplier *= saturate(g_Crest_MaximumVerticalDisplacement - 1.0);
// Fade towards screen edge where off screen samples happen. + n is fade start.
multiplier *= saturate((dot(i_PositionNDC - 0.5, -g_Crest_HorizonNormal) + 0.5) * 2.0);
}
normal.y *= multiplier;
}
// Blend at the edge of the screen to avoid artifacts.
refractOffset *= 1.0 - EdgeBlendingFactor(positionNDC, i_PixelZ);
// Since we lose detail at a distance, boosting refraction helps visually.
strength *= lerp(i_Scale, i_Scale * 2.0, i_LodAlpha) * 0.25;
const float2 positionNDCRefracted = FoveatedRemapLinearToNonUniform(positionNDC + refractOffset);
float sceneDepthRawRefracted = SHADERGRAPH_SAMPLE_SCENE_DEPTH(positionNDCRefracted);
// Restrict to a reasonable maximum.
strength = min(strength, i_RefractionStrength * 4.0);
float2 uv = GetRefractionCoordinates(i_View, normal, i_PositionWS, eta, strength);
o_PositionSS = min(uv * _ScreenSize.xy, _ScreenSize.xy - 1.0);
#if CREST_BIRP
float deviceDepth = LoadSceneDepth(o_PositionSS);
#else
float deviceDepth = SHADERGRAPH_SAMPLE_SCENE_DEPTH(uv);
#endif
#if (CREST_PORTALS != 0)
#if _ALPHATEST_ON
// Portals
Portal::EvaluateRefraction(positionNDCRefracted, i_SceneZRaw, i_Underwater, sceneDepthRawRefracted, o_Caustics);
Portal::EvaluateRefraction(uv, i_SceneZRaw, i_Underwater, deviceDepth, o_Caustics);
#endif
#endif
float linearDepth = Utility::CrestLinearEyeDepth(deviceDepth);
float depthDifference = linearDepth - i_PixelZ;
const float sceneZRefract = Utility::CrestLinearEyeDepth(sceneDepthRawRefracted);
normal *= saturate(depthDifference);
// Depth fog & caustics - only if view ray starts from above water.
// Compute depth fog alpha based on refracted position if it landed on an
// underwater surface, or on unrefracted depth otherwise.
if (sceneZRefract > i_PixelZ)
{
// Refracted.
o_SceneDistance = sceneZRefract - i_PixelZ;
o_SceneColor = SHADERGRAPH_SAMPLE_SCENE_COLOR(positionNDCRefracted);
uv = GetRefractionCoordinates(i_View, normal, i_PositionWS, eta, strength);
positionNDC = positionNDCRefracted;
sceneDepthRaw = sceneDepthRawRefracted;
}
else
{
// Unrefracted.
// It seems that when MSAA is enabled this can sometimes be negative.
o_SceneDistance = max(i_SceneZ - i_PixelZ, 0.0);
o_SceneColor = i_SceneColorUnrefracted;
o_PositionSS = min(uv * _ScreenSize.xy, _ScreenSize.xy - 1.0);
// NOTE: Causes refraction artifact with caustics. Cannot remember exactly why this was added.
// o_Caustics = false;
positionNDC = FoveatedRemapLinearToNonUniform(positionNDC);
}
#if CREST_BIRP
deviceDepth = LoadSceneDepth(o_PositionSS);
#else
deviceDepth = SHADERGRAPH_SAMPLE_SCENE_DEPTH(uv);
#endif
if (i_Underwater)
{
// Depth fog is handled by underwater shader.
o_SceneDistance = i_PixelZ;
}
linearDepth = Utility::CrestLinearEyeDepth(deviceDepth);
// It seems that when MSAA is enabled this can sometimes be negative.
depthDifference = max(linearDepth - i_PixelZ, 0.0);
o_ScenePositionWS = ComputeWorldSpacePosition(positionNDC, sceneDepthRaw, UNITY_MATRIX_I_VP);
#if CREST_BIRP
// Sampling artifacts which manifest as a fine outline around refractions. Always
// affects BIRP unless we use Load. Does not affect URP unless downsampling or MSAA
// is used, but Load exposes us to RT scaling. Best to use Sample with HDRP too.
o_SceneColor = LoadSceneColor(o_PositionSS).rgb;
#else
// Sampling artifacts if downsampling or MSAA used. Load does not help. And we get
// outlines around all objects irrespective of refraction.
o_SceneColor = SHADERGRAPH_SAMPLE_SCENE_COLOR(uv).rgb;
#endif
o_SceneDistance = depthDifference;
o_ScenePositionWS = ComputeWorldSpacePosition(uv, deviceDepth, UNITY_MATRIX_I_VP);
#if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0)
o_ScenePositionWS += _WorldSpaceCameraPos;
#endif
@@ -111,3 +166,4 @@ void RefractedScene
m_CrestNameSpaceEnd
#endif
#endif

View File

@@ -58,4 +58,8 @@
#endif
#endif
#if !defined(CREST_HDRP) && (SHADERPASS == SHADERPASS_MOTION_VECTORS)
#define _TRANSPARENT_WRITES_MOTION_VEC
#endif
#endif // CREST_SHADERGRAPH_CONSTANTS_H

View File

@@ -4,39 +4,34 @@
// Guard against missing uniforms.
#ifdef SHADERPASS
#define m_Properties \
#define m_Properties(iomod) \
const float3 i_PositionWS, \
const half3 i_Normal, \
const float3 i_ObjectPosition, \
const float3 i_CameraPosition, \
const float i_Time, \
out float3 o_PositionWS, \
out float2 o_UndisplacedXZ, \
out float o_LodAlpha, \
out half o_WaterLevelOffset, \
out float2 o_WaterLevelDerivatives, \
out half2 o_Flow
iomod float3 o_PositionWS, \
iomod half3 o_Normal, \
iomod float2 o_UndisplacedXZ, \
iomod float o_LodAlpha, \
iomod half o_WaterLevelOffset, \
iomod half2 o_Flow
// Guard against Shader Graph preview.
#ifndef SHADERGRAPH_PREVIEW
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Shim.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Keywords.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Macros.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Globals.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/InputsDriven.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Helpers.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Cascade.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Geometry.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Utility/Depth.hlsl"
#ifndef CREST_HDRP
#if (SHADERPASS == SHADERPASS_MOTION_VECTORS)
#define _TRANSPARENT_WRITES_MOTION_VEC 1
#endif
#endif
#if _TRANSPARENT_WRITES_MOTION_VEC
#define m_Slice clamp((int)_Crest_LodIndex + (isMotionVectors ? g_Crest_LodChange : 0), 0, g_Crest_LodCount)
#if d_Crest_MotionVectors
#define m_Slice ComputeSlice(_Crest_LodIndex, isMotionVectors ? g_Crest_LodChange : 0, g_Crest_LodCount)
#define m_Make(slice) Make(slice, isMotionVectors)
#else
#define m_Slice _Crest_LodIndex
@@ -45,17 +40,14 @@
m_CrestNameSpace
void Vertex(m_Properties)
#if !d_Crest_CustomMesh
void Vertex(m_Properties(inout))
{
// Chunk mesh has no normals.
o_Normal = half3(0.0, 1.0, 0.0);
// This will get called twice.
// With current and previous time respectively.
o_UndisplacedXZ = 0.0;
o_LodAlpha = 0.0;
o_WaterLevelOffset = 0.0;
o_WaterLevelDerivatives = 0.0;
o_Flow = 0.0;
const bool isMotionVectors = i_Time < _Time.y;
const float slice0 = m_Slice;
@@ -63,8 +55,6 @@ void Vertex(m_Properties)
const Cascade cascade0 = Cascade::m_Make(slice0);
const Cascade cascade1 = Cascade::m_Make(slice1);
o_PositionWS = i_PositionWS;
// Vertex snapping and LOD transition.
SnapAndTransitionVertLayout
(
@@ -75,20 +65,7 @@ void Vertex(m_Properties)
o_LodAlpha
);
// Fix precision errors at edges.
{
// Scale up by small "epsilon" to solve numerical issues. Expand slightly about tile center.
// :WaterGridPrecisionErrors
const float2 tileCenterXZ = i_ObjectPosition.xz;
const float2 cameraPositionXZ = abs(i_CameraPosition.xz);
// Scale "epsilon" by distance from zero. There is an issue where overlaps can cause SV_IsFrontFace
// to be flipped (needs to be investigated). Gaps look bad from above surface, and overlaps look bad
// from below surface. We want to close gaps without introducing overlaps. A fixed "epsilon" will
// either not solve gaps at large distances or introduce too many overlaps at small distances. Even
// with scaling, there are still unsolvable overlaps underwater (especially at large distances).
// 100,000 (0.00001) is the maximum position before Unity warns the user of precision issues.
o_PositionWS.xz = lerp(tileCenterXZ, o_PositionWS.xz, lerp(1.0, 1.01, max(cameraPositionXZ.x, cameraPositionXZ.y) * 0.00001));
}
PatchVerticeLayout(i_ObjectPosition.xz, i_CameraPosition.xz, o_PositionWS.xz);
o_UndisplacedXZ = o_PositionWS.xz;
@@ -96,51 +73,56 @@ void Vertex(m_Properties)
const float weight0 = (1.0 - o_LodAlpha) * cascade0._Weight;
const float weight1 = (1.0 - weight0) * cascade1._Weight;
half2 derivatives = 0.0;
// Data that needs to be sampled at the undisplaced position.
if (weight0 > m_CrestSampleLodThreshold)
{
#if _TRANSPARENT_WRITES_MOTION_VEC
#if d_Crest_MotionVectors
if (isMotionVectors)
{
Cascade::MakeAnimatedWavesSource(slice0).SampleDisplacement(o_UndisplacedXZ, weight0, o_PositionWS, o_WaterLevelDerivatives);
Cascade::MakeAnimatedWavesSource(slice0).SampleDisplacement(o_UndisplacedXZ, weight0, o_PositionWS);
}
else
#endif
{
Cascade::MakeAnimatedWaves(slice0).SampleDisplacement(o_UndisplacedXZ, weight0, o_PositionWS, o_WaterLevelDerivatives);
Cascade::MakeAnimatedWaves(slice0).SampleDisplacement(o_UndisplacedXZ, weight0, o_PositionWS, derivatives, o_WaterLevelOffset);
}
}
if (weight1 > m_CrestSampleLodThreshold)
{
#if _TRANSPARENT_WRITES_MOTION_VEC
#if d_Crest_MotionVectors
if (isMotionVectors)
{
Cascade::MakeAnimatedWavesSource(slice1).SampleDisplacement(o_UndisplacedXZ, weight1, o_PositionWS, o_WaterLevelDerivatives);
Cascade::MakeAnimatedWavesSource(slice1).SampleDisplacement(o_UndisplacedXZ, weight1, o_PositionWS);
}
else
#endif
{
Cascade::MakeAnimatedWaves(slice1).SampleDisplacement(o_UndisplacedXZ, weight1, o_PositionWS, o_WaterLevelDerivatives);
Cascade::MakeAnimatedWaves(slice1).SampleDisplacement(o_UndisplacedXZ, weight1, o_PositionWS, derivatives, o_WaterLevelOffset);
}
}
// Account for water level changes which change angle of water surface, impacting normal.
// true = normalize.
o_Normal.xz += -derivatives;
o_Normal = TransformWorldToObjectNormal(o_Normal, true);
#if d_Crest_FlowLod
// Data that needs to be sampled at the displaced position.
if (weight0 > m_CrestSampleLodThreshold)
{
#if CREST_FLOW_ON
Cascade::MakeFlow(slice0).SampleFlow(o_UndisplacedXZ, weight0, o_Flow);
#endif
}
if (weight1 > m_CrestSampleLodThreshold)
{
#if CREST_FLOW_ON
Cascade::MakeFlow(slice1).SampleFlow(o_UndisplacedXZ, weight1, o_Flow);
#endif
}
#endif // d_Crest_FlowLod
#if _TRANSPARENT_WRITES_MOTION_VEC
#if d_Crest_MotionVectors
if (isMotionVectors)
{
o_PositionWS.xz -= g_Crest_WaterCenter.xz;
@@ -150,35 +132,39 @@ void Vertex(m_Properties)
}
#endif
}
#endif
m_CrestNameSpaceEnd
#endif // SHADERGRAPH_PREVIEW
void Vertex_float(m_Properties)
void Vertex_float(m_Properties(out))
{
#if SHADERGRAPH_PREVIEW
o_PositionWS = 0.0;
o_UndisplacedXZ = 0.0;
o_Normal = i_Normal;
o_PositionWS = i_PositionWS;
o_UndisplacedXZ = i_PositionWS.xz;
o_LodAlpha = 0.0;
o_WaterLevelOffset = 0.0;
o_WaterLevelDerivatives = 0.0;
o_Flow = 0.0;
#else // SHADERGRAPH_PREVIEW
#if !d_Crest_CustomMesh
#if !SHADERGRAPH_PREVIEW
m_Crest::Vertex
(
i_PositionWS,
i_Normal,
i_ObjectPosition,
i_CameraPosition,
i_Time,
o_PositionWS,
o_Normal,
o_UndisplacedXZ,
o_LodAlpha,
o_WaterLevelOffset,
o_WaterLevelDerivatives,
o_Flow
);
#endif // SHADERGRAPH_PREVIEW
#endif // d_Crest_CustomMesh
}
#undef m_Properties

View File

@@ -4,6 +4,7 @@
#ifndef CREST_WATER_VOLUME_LIGHTING_H
#define CREST_WATER_VOLUME_LIGHTING_H
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Keywords.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Macros.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Globals.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Utility.hlsl"
@@ -11,10 +12,10 @@
m_CrestNameSpace
// Schlick phase function.
float SchlickPhase(float phaseG, float cosTheta)
half SchlickPhase(half phaseG, half cosTheta)
{
const float schlickK = 1.5 * phaseG - 0.5 * phaseG * phaseG * phaseG;
const float phaseFactor = 1.0 + schlickK * cosTheta;
const half schlickK = 1.5 * phaseG - 0.5 * phaseG * phaseG * phaseG;
const half phaseFactor = 1.0 + schlickK * cosTheta;
return (1.0 - schlickK * schlickK) / (4.0 * PI * phaseFactor * phaseFactor);
}
@@ -42,36 +43,49 @@ half3 VolumeLighting
const half3 i_PrimaryLightDirection,
const half3 i_PrimaryLightIntensity,
const half3 i_AdditionalLight,
const half i_AdditionalLightBlend,
const half i_AmbientLightingTerm,
const half i_PrimaryLightingTerm,
const half i_AdditionalLightingTerm,
const half3 i_SunBoost,
const half i_ShadowsAffectAmbientLightingFactor
)
{
const half3 extinction = i_Extinction;
const float ambientLightShadow = lerp
half ambientLightShadow = 1.0;
#if d_Crest_ShadowLod
ambientLightShadow = lerp
(
1.0,
i_DirectionalLightShadow,
saturate(min(min(extinction.x, extinction.y), extinction.z) * i_ShadowsAffectAmbientLightingFactor * g_Crest_DynamicSoftShadowsFactor)
);
#ifdef d_IsAdditionalLight
const float3 inscattered = i_PrimaryLightIntensity;
#else
// Sun
const float sunPhase = SchlickPhase(i_PhaseG, dot(i_PrimaryLightDirection, i_ViewDirectionWS));
const float3 inScatteredSun = (1.0 + i_SunBoost) * sunPhase * i_PrimaryLightIntensity * i_PrimaryLightingTerm;
const float3 inScatteredAmbient = i_AmbientLighting * i_AmbientLightingTerm * ambientLightShadow;
// Total inscattered
const float3 inscattered = (inScatteredAmbient + i_AdditionalLight + inScatteredSun * i_DirectionalLightShadow);
#endif
const float3 scatteringAmount = saturate(i_Scattering / max(extinction, 0.00001));
#ifdef d_IsAdditionalLight
half3 inScattered = 0.0;
half3 inScatteredAdditional = i_PrimaryLightIntensity;
#else
// Sun
const half sunPhase = SchlickPhase(i_PhaseG, dot(i_PrimaryLightDirection, i_ViewDirectionWS));
const half3 inScatteredSun = (1.0 + i_SunBoost) * sunPhase * i_PrimaryLightIntensity * i_PrimaryLightingTerm;
const half3 inScatteredAmbient = i_AmbientLighting * i_AmbientLightingTerm * ambientLightShadow;
return inscattered * scatteringAmount;
half3 inScattered = inScatteredAmbient + inScatteredSun * i_DirectionalLightShadow;
half3 inScatteredAdditional = i_AdditionalLight;
#endif
const half3 scatteringAmount = saturate(i_Scattering / max(extinction, 0.00001));
inScattered *= scatteringAmount;
#if d_Crest_AdditionalLights
inScatteredAdditional *= i_AdditionalLightingTerm;
inScatteredAdditional *= (1.0 - i_AdditionalLightBlend) + scatteringAmount * i_AdditionalLightBlend;
#endif
return inScattered + inScatteredAdditional;
}
half PinchSSS

View File

@@ -0,0 +1,36 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
#pragma exclude_renderers glcore gles3
#pragma kernel CrestAdd
#pragma multi_compile_local d_Float1 d_Float2 d_Float3 d_Float4
#if d_Float1
#define m_Type float
#elif d_Float2
#define m_Type float2
#elif d_Float3
#define m_Type float3
#elif d_Float4
#define m_Type float4
#endif
#include "HLSLSupport.cginc"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Utility/Macros.hlsl"
Texture2DArray<m_Type> _Crest_Source;
RWTexture2DArray<m_Type> _Crest_Target;
m_UtilityNameSpace
void Add(uint3 id)
{
_Crest_Target[id] += _Crest_Source[id];
}
m_UtilityNameSpaceEnd
m_UtilityKernelDefault(Add)

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d18c1734c0d4d4e7b9a09a5da1ad1b2c
ComputeShaderImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,60 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
#pragma exclude_renderers glcore gles3
#pragma kernel BlurHorizontal
#pragma kernel BlurVertical
#pragma multi_compile_local d_Float1 d_Float2 d_Float3 d_Float4
#if d_Float1
#define m_Type float
#elif d_Float2
#define m_Type float2
#elif d_Float3
#define m_Type float3
#elif d_Float4
#define m_Type float4
#endif
Texture2DArray<m_Type> _Crest_Source;
RWTexture2DArray<m_Type> _Crest_Target;
uint _Crest_Resolution;
static const float w0 = 0.4026;
static const float w1 = 0.2442;
static const float w2 = 0.0545;
uint PositiveOffset(uint value, uint offset)
{
return min(value + offset, _Crest_Resolution - 1);
}
uint NegativeOffset(uint value, uint offset)
{
return value < offset ? 0 : value - offset;
}
[numthreads(8, 8, 1)]
void BlurHorizontal(const uint3 id : SV_DispatchThreadID)
{
_Crest_Target[id] =
_Crest_Source[id] * w0 +
_Crest_Source[uint3(PositiveOffset(id.x, 1), id.y, id.z)] * w1 +
_Crest_Source[uint3(NegativeOffset(id.x, 1), id.y, id.z)] * w1 +
_Crest_Source[uint3(PositiveOffset(id.x, 2), id.y, id.z)] * w2 +
_Crest_Source[uint3(NegativeOffset(id.x, 2), id.y, id.z)] * w2;
}
[numthreads(8, 8, 1)]
void BlurVertical(const uint3 id : SV_DispatchThreadID)
{
_Crest_Target[id] =
_Crest_Source[id] * w0 +
_Crest_Source[uint3(id.x, PositiveOffset(id.y, 1), id.z)] * w1 +
_Crest_Source[uint3(id.x, NegativeOffset(id.y, 1), id.z)] * w1 +
_Crest_Source[uint3(id.x, PositiveOffset(id.y, 2), id.z)] * w2 +
_Crest_Source[uint3(id.x, NegativeOffset(id.y, 2), id.z)] * w2;
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 5a49c73b133c743caa1d82459943eabf
ComputeShaderImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -3,19 +3,33 @@
// Clear specific components using a mask.
#pragma exclude_renderers glcore gles3
#pragma kernel CrestClearTarget
#pragma kernel CrestClearTargetBoundaryX d_BoundaryX
#pragma kernel CrestClearTargetBoundaryY d_BoundaryY
#pragma multi_compile_local d_Float1 d_Float2 d_Float3 d_Float4
#if d_Float1
#define m_Type float
#elif d_Float2
#define m_Type float2
#elif d_Float3
#define m_Type float3
#elif d_Float4
#define m_Type float4
#endif
#include "HLSLSupport.cginc"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Utility/Macros.hlsl"
RWTexture2DArray<float4> _Crest_Target;
RWTexture2DArray<m_Type> _Crest_Target;
CBUFFER_START(CrestPerMaterial)
float4 _Crest_ClearMask;
float4 _Crest_ClearColor;
m_Type _Crest_ClearMask;
m_Type _Crest_ClearColor;
uint _Crest_Resolution;
uint _Crest_TargetSlice;
CBUFFER_END

View File

@@ -28,16 +28,16 @@
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Utility/Depth.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Volume/UnderwaterShared.hlsl"
#if !d_Crest_WaterSurface
#define CREST_INTEGRATE_COLOR_AFTER_FOG(color)
#define CREST_INTEGRATE_COLOR_FINAL(color)
#endif
m_CrestNameSpace
static bool s_IsUnderWater;
static float s_FogDistance;
static half s_FogMultiplier;
static float2 s_PositionSS;
static float3 s_PositionWS;
static half3 s_ViewWS;
static float s_DepthRaw;
static half3 s_VolumeOpacity;
static half3 s_VolumeLighting;
float3 ApplyFog(float3 color)
{
@@ -46,22 +46,11 @@ float3 ApplyFog(float3 color)
{
return color;
}
else
#endif
return ApplyUnderwaterEffect
(
color,
s_DepthRaw,
0, // Caustics only
s_FogDistance,
s_ViewWS,
s_PositionSS,
s_PositionWS,
false, // No caustics
true, // TODO: implement
true, // TODO: implement
s_FogMultiplier
);
{
return lerp(color, s_VolumeLighting, s_VolumeOpacity * (s_IsUnderWater ? 1.0 : 0.0));
}
}
float3 NoFog(float3 color)
@@ -122,12 +111,23 @@ void SetUpFog(const float2 i_PositionNDC, const float3 i_PositionWS, const float
}
s_IsUnderWater = true;
s_PositionSS = positionSS;
s_PositionWS = i_PositionWS;
s_ViewWS = GetWorldSpaceNormalizeViewDir(i_PositionWS);
s_FogDistance = fogDistance;
s_DepthRaw = i_DepthRaw;
s_FogMultiplier = i_Multiplier;
ApplyUnderwaterEffect
(
0, // Color
0, // TIR only
0, // Caustics only
fogDistance,
GetWorldSpaceNormalizeViewDir(i_PositionWS),
positionSS,
i_PositionWS,
false, // No caustics
true, // TODO: implement
true, // TODO: implement
i_Multiplier,
s_VolumeOpacity,
s_VolumeLighting
);
}
m_CrestNameSpaceEnd
@@ -139,6 +139,7 @@ m_CrestNameSpaceEnd
#endif
#if CREST_BIRP
// Color is RGBA.
#ifdef UNITY_PASS_FORWARDADD
#define m_Unity_FogColor fixed4(0, 0, 0, 0)
#else
@@ -155,27 +156,70 @@ if (m_Crest::s_IsUnderWater) \
else \
{ \
UNITY_APPLY_FOG_COLOR(coord, color, m_Unity_FogColor); \
}
CREST_INTEGRATE_COLOR_AFTER_FOG(color.rgb) \
} \
CREST_INTEGRATE_COLOR_FINAL(color.rgb)
#else
#define UNITY_APPLY_FOG(coord, color) \
UNITY_APPLY_FOG_COLOR(coord, color, m_Unity_FogColor); \
color.rgb = m_Crest::ApplyFog(color.rgb);
color.rgb = m_Crest::ApplyFog(color.rgb); \
if (!m_Crest::s_IsUnderWater) \
{ \
CREST_INTEGRATE_COLOR_AFTER_FOG(color.rgb) \
} \
CREST_INTEGRATE_COLOR_FINAL(color.rgb)
#endif // CREST_DISCARD_ATMOSPHERIC_SCATTERING
#endif // CREST_BIRP
#if CREST_HDRP
// Color is RGBA.
#if (CREST_DISCARD_ATMOSPHERIC_SCATTERING != 0)
#define EvaluateAtmosphericScattering(i, V, color) m_Crest::s_IsUnderWater ? float4(m_Crest::ApplyFog(color.rgb), color.a) : EvaluateAtmosphericScattering(i, V, color)
#define EvaluateAtmosphericScattering(i, V, color) color; \
if (m_Crest::s_IsUnderWater) \
{ \
color.rgb = m_Crest::ApplyFog(color.rgb); \
} \
else \
{ \
color = EvaluateAtmosphericScattering(i, V, color); \
CREST_INTEGRATE_COLOR_AFTER_FOG(color.rgb) \
} \
CREST_INTEGRATE_COLOR_FINAL(color.rgb)
#else
#define EvaluateAtmosphericScattering(i, V, color) EvaluateAtmosphericScattering(i, V, color); color.rgb = m_Crest::ApplyFog(color.rgb)
#define EvaluateAtmosphericScattering(i, V, color) color; \
color = EvaluateAtmosphericScattering(i, V, color); \
color.rgb = m_Crest::ApplyFog(color.rgb); \
if (!m_Crest::s_IsUnderWater) \
{ \
CREST_INTEGRATE_COLOR_AFTER_FOG(color.rgb); \
} \
CREST_INTEGRATE_COLOR_FINAL(color.rgb)
#endif
#endif
#if CREST_URP
// Color is RGB.
#if (CREST_DISCARD_ATMOSPHERIC_SCATTERING != 0)
#define MixFog(color, coord) m_Crest::s_IsUnderWater ? m_Crest::ApplyFog(color) : MixFog(color, coord)
#define MixFog(color, coord) color; \
if (m_Crest::s_IsUnderWater) \
{ \
color = m_Crest::ApplyFog(color); \
} \
else \
{ \
color = MixFog(color, coord); \
CREST_INTEGRATE_COLOR_AFTER_FOG(color) \
} \
CREST_INTEGRATE_COLOR_FINAL(color)
#else
#define MixFog(color, coord) MixFog(color, coord); color.rgb = m_Crest::ApplyFog(color.rgb)
#define MixFog(color, coord) color; \
color = MixFog(color, coord); \
color = m_Crest::ApplyFog(color); \
if (!m_Crest::s_IsUnderWater) \
{ \
CREST_INTEGRATE_COLOR_AFTER_FOG(color); \
} \
CREST_INTEGRATE_COLOR_FINAL(color)
#endif
#endif
@@ -216,6 +260,11 @@ void CrestNodeIntegrateWaterVolume_float
o_Color = i_Color;
o_Emission = i_Emission;
if (i_Multiplier == 0)
{
return;
}
#ifndef SHADERGRAPH_PREVIEW
m_Crest::SetUpFog(i_PositionNDC, i_PositionWS, i_DepthRaw, i_Multiplier);
#endif

View File

@@ -1,6 +1,8 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
#pragma exclude_renderers glcore gles3
#pragma kernel CrestWaterLineBRP _BRP
#pragma kernel CrestWaterLineHRP _HRP
#pragma kernel CrestWaterLineURP _URP

View File

@@ -4,14 +4,16 @@
#ifndef d_WaveHarmonic_Crest_Mask
#define d_WaveHarmonic_Crest_Mask
#if d_LodInput
#define d_RequirePositionWS 1
#endif
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Settings.Crest.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Macros.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Constants.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/InputsDriven.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Globals.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Helpers.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Cascade.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Geometry.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Vertex/Surface.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Utility/Depth.hlsl"
#if (CREST_PORTALS != 0)
@@ -20,89 +22,12 @@
m_CrestNameSpace
struct Attributes
{
// The old unity macros require this name and type.
float4 positionCS : POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 positionCS : SV_POSITION;
#if d_LodInput
float3 positionWS : TEXCOORD;
#endif
UNITY_VERTEX_OUTPUT_STEREO
};
Varyings Vertex(const Attributes i_Input)
{
// This will work for all pipelines.
Varyings output = (Varyings)0;
UNITY_SETUP_INSTANCE_ID(i_Input);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
const uint slice0 = _Crest_LodIndex;
const uint slice1 = _Crest_LodIndex + 1;
const Cascade cascade0 = Cascade::Make(slice0);
const Cascade cascade1 = Cascade::Make(slice1);
float3 positionWS = mul(UNITY_MATRIX_M, float4(i_Input.positionCS.xyz, 1.0)).xyz;
#if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0)
positionWS.xz += _WorldSpaceCameraPos.xz;
#endif
float alpha;
SnapAndTransitionVertLayout(_Crest_ChunkMeshScaleAlpha, cascade0, _Crest_ChunkGeometryGridWidth, positionWS, alpha);
{
// Scale up by small "epsilon" to solve numerical issues. Expand slightly about tile center.
// :WaterGridPrecisionErrors
float2 tileCenterXZ = UNITY_MATRIX_M._m03_m23;
#if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0)
tileCenterXZ += _WorldSpaceCameraPos.xz;
#endif
const float2 cameraPositionXZ = abs(_WorldSpaceCameraPos.xz);
positionWS.xz = lerp(tileCenterXZ, positionWS.xz, lerp(1.0, 1.01, max(cameraPositionXZ.x, cameraPositionXZ.y) * 0.00001));
}
const float weight0 = (1.0 - alpha) * cascade0._Weight;
const float weight1 = (1.0 - weight0) * cascade1._Weight;
const float2 positionXZ = positionWS.xz;
// Data that needs to be sampled at the undisplaced position.
if (weight0 > m_CrestSampleLodThreshold)
{
Cascade::MakeAnimatedWaves(slice0).SampleDisplacement(positionXZ, weight0, positionWS);
}
if (weight1 > m_CrestSampleLodThreshold)
{
Cascade::MakeAnimatedWaves(slice1).SampleDisplacement(positionXZ, weight1, positionWS);
}
#if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0)
positionWS.xz -= _WorldSpaceCameraPos.xz;
#endif
output.positionCS = mul(UNITY_MATRIX_VP, float4(positionWS, 1.0));
#if d_LodInput
output.positionWS = positionWS;
#endif
return output;
}
half4 Fragment(const Varyings i_Input, const bool i_FrontFace)
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i_Input);
#if d_LodInput
return half4(i_Input.positionWS.y - g_Crest_WaterCenter.y, 0, 0, 1);
return half4(i_Input._PositionWS.y - g_Crest_WaterCenter.y, 0, 0, 1);
#endif
half result = 0.0;
@@ -111,7 +36,7 @@ half4 Fragment(const Varyings i_Input, const bool i_FrontFace)
#if !d_Tunnel
if (m_CrestPortal)
{
Portal::EvaluateMask(i_Input.positionCS);
Portal::EvaluateMask(i_Input._PositionCS);
}
#endif
#endif
@@ -127,11 +52,11 @@ half4 Fragment(const Varyings i_Input, const bool i_FrontFace)
#if (CREST_PORTALS != 0)
#if d_Crest_NegativeVolumePass
result = Portal::FixMaskForNegativeVolume(result, i_Input.positionCS.xy);
result = Portal::FixMaskForNegativeVolume(result, i_Input._PositionCS.xy);
#endif
#if d_Tunnel
const float2 positionSS = i_Input.positionCS.xy;
const float2 positionSS = i_Input._PositionCS.xy;
const float ffz = LOAD_DEPTH_TEXTURE_X(_Crest_PortalFogBeforeTexture, positionSS);
const float bfz = LOAD_DEPTH_TEXTURE_X(_Crest_PortalFogAfterTexture, positionSS);
if (ffz <= 0.0 && bfz > 0.0)

Some files were not shown because too many files have changed in this diff Show More