249 lines
6.9 KiB
HLSL
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
|