Files
2026-03-05 00:14:42 +08:00

182 lines
5.6 KiB
HLSL

// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
#ifndef CREST_WATER_CAUSTICS_H
#define CREST_WATER_CAUSTICS_H
#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/Globals.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Texture.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Flow.hlsl"
#if (CREST_SHIFTING_ORIGIN != 0)
#include "Packages/com.waveharmonic.crest.shifting-origin/Runtime/Shaders/ShiftingOrigin.hlsl"
#endif
m_CrestNameSpace
half3 Caustics
(
const float3 i_ScenePositionWS,
const float i_SurfacePositionY,
const half3 i_LightIntensity,
const half3 i_LightDirection,
const half i_LightShadow,
const float i_SceneDepth,
const TiledTexture i_CausticsTexture,
const half i_TextureAverage,
const half i_Strength,
const half i_FocalDepth,
const half i_DepthOfField,
const TiledTexture i_DistortionTexture,
const half i_DistortionStrength,
const half i_Blur,
const bool i_Underwater
)
{
half sceneDepth = i_SurfacePositionY - i_ScenePositionWS.y;
// Compute mip index manually, with bias based on sea floor depth. We compute it manually because if it is computed automatically it produces ugly patches
// where samples are stretched/dilated. The bias is to give a focusing effect to caustics - they are sharpest at a particular depth. This doesn't work amazingly
// well and could be replaced.
float mipLod = log2(i_SceneDepth) + abs(sceneDepth - i_FocalDepth) / i_DepthOfField + i_Blur;
// Project along light dir, but multiply by a fudge factor reduce the angle bit - compensates for fact that in real life
// caustics come from many directions and don't exhibit such a strong directonality
// Removing the fudge factor (4.0) will cause the caustics to move around more with the waves. But this will also
// result in stretched/dilated caustics in certain areas. This is especially noticeable on angled surfaces.
float2 lightProjection = i_LightDirection.xz * sceneDepth / (4.0 * i_LightDirection.y);
float3 cuv1 = 0.0; float3 cuv2 = 0.0;
{
float2 surfacePosXZ = i_ScenePositionWS.xz;
float surfacePosScale = 1.37;
#if (CREST_SHIFTING_ORIGIN != 0)
// Apply tiled floating origin offset. Always needed.
surfacePosXZ -= ShiftingOriginOffset(i_CausticsTexture);
// Scale was causing popping.
surfacePosScale = 1.0;
#endif
surfacePosXZ += lightProjection;
float scale = i_CausticsTexture._scale / 10.0;
const float speed = g_Crest_Time * i_CausticsTexture._speed;
cuv1 = float3
(
surfacePosXZ / scale + float2(0.044 * speed + 17.16, -0.169 * speed),
mipLod
);
cuv2 = float3
(
surfacePosScale * surfacePosXZ / scale + float2(0.248 * speed, 0.117 * speed),
mipLod
);
}
if (i_Underwater)
{
float2 surfacePosXZ = i_ScenePositionWS.xz;
#if (CREST_SHIFTING_ORIGIN != 0)
// Apply tiled floating origin offset. Always needed.
surfacePosXZ -= ShiftingOriginOffset(i_DistortionTexture);
#endif
surfacePosXZ += lightProjection;
float scale = i_DistortionTexture._scale / 10.0;
half2 causticN = i_DistortionStrength * UnpackNormal(i_DistortionTexture.Sample(surfacePosXZ / scale)).xy;
cuv1.xy += 1.30 * causticN;
cuv2.xy += 1.77 * causticN;
}
half causticsStrength = i_Strength;
// Occlusion.
{
causticsStrength *= i_LightShadow;
}
return 1.0 + causticsStrength *
(
0.5 * i_CausticsTexture.SampleLevel(cuv1.xy, cuv1.z).xyz +
0.5 * i_CausticsTexture.SampleLevel(cuv2.xy, cuv2.z).xyz
- i_TextureAverage
);
}
half3 Caustics
(
const Flow i_Flow,
const float3 i_ScenePositionWS,
const float i_SurfacePositionY,
const half3 i_LightIntensity,
const half3 i_LightDirection,
const half i_LightShadow,
const float i_SceneDepth,
const TiledTexture i_CausticsTexture,
const half i_TextureAverage,
const half i_Strength,
const half i_FocalDepth,
const half i_DepthOfField,
const TiledTexture i_DistortionTexture,
const half i_DistortionStrength,
const half i_Blur,
const bool i_Underwater
)
{
half blur = 0.0;
half3 flow = half3(i_Flow._Flow.x, 0, i_Flow._Flow.y);
if (i_Blur > 0.0)
{
// Calculate blur in flowing water as will likely be more disturbed, resulting in
// caustics being less defined.
blur = length(i_Flow._Flow) * i_Blur;
}
return Caustics
(
i_ScenePositionWS - flow * i_Flow._Offset0,
i_SurfacePositionY,
i_LightIntensity,
i_LightDirection,
i_LightShadow,
i_SceneDepth,
i_CausticsTexture,
i_TextureAverage,
i_Strength,
i_FocalDepth,
i_DepthOfField,
i_DistortionTexture,
i_DistortionStrength,
blur,
i_Underwater
) * i_Flow._Weight0 + Caustics
(
i_ScenePositionWS - flow * i_Flow._Offset1,
i_SurfacePositionY,
i_LightIntensity,
i_LightDirection,
i_LightShadow,
i_SceneDepth,
i_CausticsTexture,
i_TextureAverage,
i_Strength,
i_FocalDepth,
i_DepthOfField,
i_DistortionTexture,
i_DistortionStrength,
blur,
i_Underwater
) * i_Flow._Weight1;
}
m_CrestNameSpaceEnd
#endif