Files
Fishing2/Packages/com.waveharmonic.crest/Runtime/Shaders/Volume/Mask.hlsl
2025-05-10 12:49:47 +08:00

152 lines
5.3 KiB
HLSL

// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
#ifndef CREST_UNDERWATER_MASK_SHARED_INCLUDED
#define CREST_UNDERWATER_MASK_SHARED_INCLUDED
#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/Utility/Depth.hlsl"
#if (CREST_PORTALS != 0)
#include "Packages/com.waveharmonic.crest.portals/Runtime/Shaders/Library/Portals.hlsl"
#endif
// Variable mask for when fog is applied before transparent pass and water tile might be culled.
half _Crest_MaskBelowSurface;
m_CrestNameSpace
struct Attributes
{
// The old unity macros require this name and type.
float4 vertex : POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 positionCS : SV_POSITION;
UNITY_VERTEX_OUTPUT_STEREO
};
Varyings Vertex(Attributes v)
{
// This will work for all pipelines.
Varyings output = (Varyings)0;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
const Cascade cascade0 = Cascade::Make(_Crest_LodIndex);
const Cascade cascade1 = Cascade::Make(_Crest_LodIndex + 1);
float3 worldPos = mul(UNITY_MATRIX_M, float4(v.vertex.xyz, 1.0)).xyz;
#if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0)
worldPos.xz += _WorldSpaceCameraPos.xz;
#endif
// Vertex snapping and lod transition
float lodAlpha;
SnapAndTransitionVertLayout(_Crest_ChunkMeshScaleAlpha, cascade0, _Crest_ChunkGeometryGridWidth, worldPos, lodAlpha);
{
// 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);
// 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.
worldPos.xz = lerp(tileCenterXZ, worldPos.xz, lerp(1.0, 1.01, max(cameraPositionXZ.x, cameraPositionXZ.y) * 0.00001));
}
// Calculate sample weights. params.z allows shape to be faded out (used on last lod to support pop-less scale transitions)
const float wt_smallerLod = (1.0 - lodAlpha) * cascade0._Weight;
const float wt_biggerLod = (1.0 - wt_smallerLod) * cascade1._Weight;
// Sample displacement textures, add results to current world pos / normal / foam
const float2 positionWS_XZ_before = worldPos.xz;
// Data that needs to be sampled at the undisplaced position
if (wt_smallerLod > m_CrestSampleLodThreshold)
{
Cascade::MakeAnimatedWaves(_Crest_LodIndex).SampleDisplacement(positionWS_XZ_before, wt_smallerLod, worldPos);
}
if (wt_biggerLod > m_CrestSampleLodThreshold)
{
Cascade::MakeAnimatedWaves(_Crest_LodIndex + 1).SampleDisplacement(positionWS_XZ_before, wt_biggerLod, worldPos);
}
#if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0)
worldPos.xz -= _WorldSpaceCameraPos.xz;
#endif
output.positionCS = mul(UNITY_MATRIX_VP, float4(worldPos, 1.0));
return output;
}
half4 Fragment(const Varyings input, const bool i_isFrontFace)
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
half4 result = 0.0;
#if (CREST_PORTALS != 0)
#if !d_Tunnel
bool masked = false;
if (m_CrestPortal)
{
masked = ApplyVolumeToWaterMask(input.positionCS);
}
#endif
#endif
if (IsUnderwater(i_isFrontFace, g_Crest_ForceUnderwater))
{
result = (half4)_Crest_MaskBelowSurface;
}
else
{
result = (half4)CREST_MASK_ABOVE_SURFACE;
}
#if (CREST_PORTALS != 0)
#if d_Tunnel
const float rawFrontFaceZ = LOAD_DEPTH_TEXTURE_X(_Crest_WaterVolumeFrontFaceTexture, input.positionCS.xy);
const float rawBackFaceZ = LOAD_DEPTH_TEXTURE_X(_Crest_WaterVolumeBackFaceTexture, input.positionCS.xy);
if (rawFrontFaceZ <= 0.0 && rawBackFaceZ > 0.0)
{
result = (half4)CREST_MASK_ABOVE_SURFACE;
}
#else
if (m_CrestPortal)
{
result *= masked ? 2 : 1;
}
#endif
#endif
return result;
}
m_CrestNameSpaceEnd
m_CrestVertex
m_CrestFragmentWithFrontFace(half4)
#endif // CREST_UNDERWATER_MASK_SHARED_INCLUDED