Files
Fishing2/Packages/com.waveharmonic.crest/Runtime/Shaders/Meniscus/Meniscus.hlsl
2026-01-31 00:32:49 +08:00

249 lines
6.9 KiB
HLSL

// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
#ifndef d_WaveHarmonic_Crest_Meniscus
#define d_WaveHarmonic_Crest_Meniscus
#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/Globals.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Cascade.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Utility/Helpers.hlsl"
#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"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Data.hlsl"
#if d_Masked
TEXTURE2D_X(_Crest_WaterMaskTexture);
#endif
#if d_Crest_Lighting
// Surface/Volume parameters.
half4 _Crest_Absorption;
half4 _Crest_Scattering;
half _Crest_Anisotropy;
half _Crest_DirectTerm;
half _Crest_AmbientTerm;
half _Crest_ShadowsAffectsAmbientFactor;
// Volume parameters.
half _Crest_SunBoost;
half3 _Crest_AmbientLighting;
int _Crest_DataSliceOffset;
#endif
half _Crest_Radius;
half _Crest_RefractionStrength;
bool _Crest_PortalInverted;
m_CrestNameSpace
struct Attributes
{
#if d_Crest_Geometry
float3 positionOS : POSITION;
#else
uint id : SV_VertexID;
#endif
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 positionCS : SV_POSITION;
#if d_Crest_Geometry
float3 positionWS : TEXCOORD;
#else
float2 uv : TEXCOORD;
#endif
UNITY_VERTEX_OUTPUT_STEREO
};
Varyings Vertex(Attributes input)
{
Varyings output;
ZERO_INITIALIZE(Varyings, output);
UNITY_SETUP_INSTANCE_ID(input);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
#if d_Crest_Geometry
output.positionCS = TransformObjectToHClip(input.positionOS);
output.positionWS = TransformObjectToWorld(input.positionOS);
#else
output.positionCS = GetFullScreenTriangleVertexPosition(input.id);
output.uv = GetFullScreenTriangleTexCoord(input.id);
#endif
return output;
}
half4 Fragment(Varyings input)
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
#if d_Masked
// Prevent rendering inside of new portal modules.
if ((LOAD_TEXTURE2D_X(_Crest_WaterMaskTexture, input.positionCS.xy).r == k_Crest_MaskInsidePortal) == _Crest_PortalInverted)
{
discard;
}
#endif
float3 positionWS;
float3 directionWS;
float2 uv;
#if d_Crest_Geometry
{
positionWS = input.positionWS;
#if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0)
positionWS.xyz += _WorldSpaceCameraPos.xyz;
#endif
directionWS = GetWorldSpaceNormalizeViewDir(positionWS);
uv = input.positionCS.xy / _ScreenSize.xy;
}
#else
{
positionWS = ComputeWorldSpacePosition(input.uv, UNITY_NEAR_CLIP_VALUE, UNITY_MATRIX_I_VP);
#if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0)
positionWS.xyz += _WorldSpaceCameraPos.xyz;
#endif
directionWS = GetWorldSpaceNormalizeViewDir(positionWS);
uv = input.uv;
}
#endif
const float height = SampleWaterLineHeight(positionWS.xz).r;
// Double as we half it if below.
float radius = _Crest_Radius * 2.0;
#if d_Crest_Refraction
// Double the radius as aggressive falloff makes it much smaller.
radius *= 2.0;
#endif
float signedDistance = positionWS.y - height;
float3 viewDirWS = normalize(_WorldSpaceCameraPos - positionWS);
const float distance = abs(signedDistance);
if (signedDistance < 0)
{
radius = max(0.002, radius * 0.25);
}
if (distance > radius)
{
discard;
}
half3 color = 0.0;
#if d_Crest_Lighting
{
half3 absorption = _Crest_Absorption.xyz;
half3 scattering = _Crest_Scattering.xyz;
// Keep the same as the volume.
const int 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;
float3 lightDirection; float3 lightColor;
PrimaryLight(positionWS, lightColor, lightDirection);
const half3 extinction = VolumeExtinction(absorption, scattering);
half opacity = 1.0;
#if !d_Crest_Refraction
// Meniscus can look too dark in shallow water.
{
const float depth = Cascade::MakeDepth(sliceIndex).SampleSignedDepthFromSeaLevel(_WorldSpaceCameraPos.xz);
opacity = VolumeOpacity(extinction, depth * 0.25);
}
#endif
half shadow = 1.0;
{
// Soft in red, hard in green. But hard not computed in HDRP.
shadow = 1.0 - Cascade::MakeShadow(sliceIndex).SampleShadow(_WorldSpaceCameraPos.xz).x;
}
half3 lighting = VolumeLighting
(
extinction,
scattering,
_Crest_Anisotropy,
shadow,
lerp(half3(0, 1, 0), directionWS, opacity),
AmbientLight(_Crest_AmbientLighting),
lerp(half3(0, -1, 0), lightDirection, opacity),
lightColor,
half3(0.0, 0.0, 0.0), // Additional lights
_Crest_AmbientTerm,
_Crest_DirectTerm,
_Crest_SunBoost,
_Crest_ShadowsAffectsAmbientFactor
);
#if CREST_HDRP
lighting *= GetCurrentExposureMultiplier();
#endif
color = lighting;
}
#endif
const float falloff = 1.0 - smoothstep(0.0, radius, distance);
#if d_Crest_Refraction
{
const half3 normal = SampleWaterLineNormal(positionWS.xz, height);
float2 dir = Utility::WorldNormalToScreenDirection(positionWS, normal, UNITY_MATRIX_VP, 0.01);
const float aspect = _ScreenParams.x / _ScreenParams.y;
dir.x /= aspect;
const float2 uvRefracted = uv - dir * falloff * _Crest_RefractionStrength;
half3 scene = SampleSceneColor(uvRefracted);
if (signedDistance >= 0)
{
// Blend back in with original. Cannot seem to do this with alpha without losing
// some lighting.
scene = lerp
(
scene,
SampleSceneColor(uv),
saturate((distance / radius) * 5.0)
);
}
color = lerp(color, scene, 0.5);
}
#endif
return float4(color, falloff);
}
m_CrestNameSpaceEnd
m_CrestVertex
m_CrestFragment(half4)
#endif // d_WaveHarmonic_Crest_Meniscus