还原水插件

This commit is contained in:
2026-03-05 00:14:42 +08:00
parent 0de35591e7
commit e82f2ea6b7
270 changed files with 2773 additions and 12445 deletions

View File

@@ -4,8 +4,6 @@
#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"
@@ -20,144 +18,91 @@
#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_View,
const half3 i_SceneColorUnrefracted,
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;
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)
// View ray intersects geometry surface either above or below water surface.
float2 refractOffset = i_RefractionStrength * i_NormalWS.xz;
if (!i_Underwater)
{
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;
// 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;
}
// Since we lose detail at a distance, boosting refraction helps visually.
strength *= lerp(i_Scale, i_Scale * 2.0, i_LodAlpha) * 0.25;
// Blend at the edge of the screen to avoid artifacts.
refractOffset *= 1.0 - EdgeBlendingFactor(positionNDC, i_PixelZ);
// 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
const float2 positionNDCRefracted = FoveatedRemapLinearToNonUniform(positionNDC + refractOffset);
float sceneDepthRawRefracted = SHADERGRAPH_SAMPLE_SCENE_DEPTH(positionNDCRefracted);
#if (CREST_PORTALS != 0)
#if _ALPHATEST_ON
Portal::EvaluateRefraction(uv, i_SceneZRaw, i_Underwater, deviceDepth, o_Caustics);
// Portals
Portal::EvaluateRefraction(positionNDCRefracted, i_SceneZRaw, i_Underwater, sceneDepthRawRefracted, o_Caustics);
#endif
#endif
float linearDepth = Utility::CrestLinearEyeDepth(deviceDepth);
float depthDifference = linearDepth - i_PixelZ;
normal *= saturate(depthDifference);
const float sceneZRefract = Utility::CrestLinearEyeDepth(sceneDepthRawRefracted);
uv = GetRefractionCoordinates(i_View, normal, i_PositionWS, eta, strength);
// 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);
o_PositionSS = min(uv * _ScreenSize.xy, _ScreenSize.xy - 1.0);
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;
#if CREST_BIRP
deviceDepth = LoadSceneDepth(o_PositionSS);
#else
deviceDepth = SHADERGRAPH_SAMPLE_SCENE_DEPTH(uv);
#endif
// NOTE: Causes refraction artifact with caustics. Cannot remember exactly why this was added.
// o_Caustics = false;
positionNDC = FoveatedRemapLinearToNonUniform(positionNDC);
}
linearDepth = Utility::CrestLinearEyeDepth(deviceDepth);
// It seems that when MSAA is enabled this can sometimes be negative.
depthDifference = max(linearDepth - i_PixelZ, 0.0);
if (i_Underwater)
{
// Depth fog is handled by underwater shader.
o_SceneDistance = i_PixelZ;
}
#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);
o_ScenePositionWS = ComputeWorldSpacePosition(positionNDC, sceneDepthRaw, UNITY_MATRIX_I_VP);
#if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0)
o_ScenePositionWS += _WorldSpaceCameraPos;
#endif
@@ -166,4 +111,3 @@ void RefractedScene
m_CrestNameSpaceEnd
#endif
#endif