2060 lines
65 KiB
HLSL
2060 lines
65 KiB
HLSL
#ifndef KWS_WATER_PASS_HELPERS
|
||
#define KWS_WATER_PASS_HELPERS
|
||
|
||
//#ifndef KWS_WATER_VARIABLES
|
||
#include "KWS_WaterVariables.cginc"
|
||
//#endif
|
||
|
||
//#ifndef KWS_COMMON_HELPERS
|
||
#include "../Common/KWS_CommonHelpers.cginc"
|
||
//#endif
|
||
|
||
|
||
#ifdef KWS_BUILTIN
|
||
//#ifndef KWS_PLATFORM_SPECIFIC_HELPERS_BUILTIN
|
||
#include "../PlatformSpecific/KWS_PlatformSpecificHelpers_Builtin.cginc"
|
||
//#endif
|
||
#endif
|
||
|
||
#ifdef KWS_URP
|
||
//#ifndef KWS_PLATFORM_SPECIFIC_HELPERS_URP
|
||
#include "../PlatformSpecific/KWS_PlatformSpecificHelpers_URP.cginc"
|
||
//#endif
|
||
#endif
|
||
|
||
#ifdef KWS_HDRP
|
||
//#ifndef KWS_PLATFORM_SPECIFIC_HELPERS_HDRP
|
||
#include "../PlatformSpecific/KWS_PlatformSpecificHelpers_HDRP.cginc"
|
||
//#endif
|
||
#endif
|
||
|
||
|
||
|
||
float CalcMipLevel(float2 uv)
|
||
{
|
||
float2 dx = ddx(uv);
|
||
float2 dy = ddy(uv);
|
||
float delta = max(dot(dx, dx), dot(dy, dy));
|
||
return max(0.0, 0.5 * log2(delta));
|
||
}
|
||
|
||
|
||
////////////////////////////////////////////// FFT_Waves_Pass //////////////////////////////////////////////
|
||
#define MAX_FFT_WAVES_MAX_CASCADES 4
|
||
|
||
|
||
|
||
float4 KWS_WavesDomainSizes;
|
||
float4 KWS_WavesDomainSizesInv;
|
||
float4 KWS_WavesDomainScaledSizes;
|
||
float4 KWS_WavesDomainScaledSizesInv;
|
||
|
||
float4 KWS_WavesDomainVisibleArea;
|
||
float4 KWS_WavesDomainVisibleAreaInv;
|
||
float4 KWS_WavesDomainHeightScales;
|
||
float4 KWS_WavesDomainHeightScalesInv;
|
||
|
||
float KWS_WindSpeed;
|
||
float KWS_WavesAreaScale;
|
||
float KWS_WavesCascades;
|
||
|
||
Texture2DArray KWS_FftWavesDisplace;
|
||
Texture2DArray KWS_FftWavesNormal;
|
||
SamplerState sampler_KWS_FftWavesNormal;
|
||
float4 KWS_FftWavesDisplace_TexelSize;
|
||
float4 KWS_FftWavesNormal_TexelSize;
|
||
|
||
|
||
|
||
float3 GetFftWavesDisplacementSlice(float3 worldPos, uint slice)
|
||
{
|
||
worldPos += KWS_WaterWorldPosOffset;
|
||
return KWS_FftWavesDisplace.SampleLevel(sampler_linear_repeat, float3(worldPos.xz * KWS_WavesDomainScaledSizesInv[slice], slice), 0).xyz * KWS_WavesAreaScale;
|
||
}
|
||
|
||
float3 GetFftWavesDisplacementSliceBicubic(float3 worldPos, uint slice)
|
||
{
|
||
worldPos += KWS_WaterWorldPosOffset;
|
||
return Texture2DArraySampleLevelBicubic(KWS_FftWavesDisplace, sampler_linear_repeat, worldPos.xz * KWS_WavesDomainScaledSizesInv[slice], KWS_FftWavesDisplace_TexelSize, slice, 0).xyz;
|
||
}
|
||
|
||
inline float GetFftFade(float distanceToCamera, int lodIdx, float farDistanceMinFade = 0.0)
|
||
{
|
||
if (lodIdx == KWS_WavesCascades - 1)
|
||
{
|
||
float farDist = max(500, KW_WaterFarDistance * 0.5);
|
||
return saturate(1.0 + farDistanceMinFade - saturate(distanceToCamera / farDist));
|
||
}
|
||
else
|
||
{
|
||
float fadeLod = saturate(distanceToCamera * KWS_WavesDomainVisibleAreaInv[lodIdx]);
|
||
fadeLod = 1 - fadeLod * fadeLod * fadeLod;
|
||
return fadeLod;
|
||
}
|
||
}
|
||
|
||
inline float4 KWS_GetFftFade4(float distanceToCamera)
|
||
{
|
||
float4 fade = saturate(distanceToCamera.xxxx * KWS_WavesDomainVisibleAreaInv);
|
||
fade = 1 - KWS_Pow3(fade);
|
||
return fade;
|
||
}
|
||
|
||
float3 GetFftWavesDisplacementLast(float3 worldPos)
|
||
{
|
||
worldPos += KWS_WaterWorldPosOffset;
|
||
int lastCascadeIdx = max(0, KWS_WavesCascades - 1);
|
||
return KWS_FftWavesDisplace.SampleLevel(sampler_linear_repeat, float3(worldPos.xz * KWS_WavesDomainScaledSizesInv[lastCascadeIdx], lastCascadeIdx), 0).xyz * KWS_WavesAreaScale;
|
||
}
|
||
|
||
float3 GetFftWavesDisplacementDetailsHQ(float3 worldPos)
|
||
{
|
||
worldPos += KWS_WaterWorldPosOffset;
|
||
float3 disp = Texture2DArraySampleLevelBicubic(KWS_FftWavesDisplace, sampler_linear_repeat, worldPos.xz * KWS_WavesDomainScaledSizesInv[0], KWS_FftWavesDisplace_TexelSize, 0, 0).xyz;
|
||
if (KWS_WavesCascades > 1) disp += Texture2DArraySampleLevelBicubic(KWS_FftWavesDisplace, sampler_linear_repeat, worldPos.xz * KWS_WavesDomainScaledSizesInv[1], KWS_FftWavesDisplace_TexelSize, 1, 0).xyz;
|
||
return disp * KWS_WavesAreaScale;
|
||
}
|
||
|
||
float3 GetFftWavesDisplacementDetails(float3 worldPos)
|
||
{
|
||
worldPos += KWS_WaterWorldPosOffset;
|
||
float3 disp = KWS_FftWavesDisplace.SampleLevel(sampler_linear_repeat, float3(worldPos.xz * KWS_WavesDomainScaledSizesInv[0], 0), 0).xyz;
|
||
if (KWS_WavesCascades > 1) disp += KWS_FftWavesDisplace.SampleLevel(sampler_linear_repeat, float3(worldPos.xz * KWS_WavesDomainScaledSizesInv[1], 1), 0).xyz;
|
||
return disp * KWS_WavesAreaScale;
|
||
}
|
||
|
||
float3 GetFftWavesDisplacementBuoyancy(float3 worldPos)
|
||
{
|
||
worldPos += KWS_WaterWorldPosOffset;
|
||
|
||
float3 finalData = 0;
|
||
for (int idx = KWS_WavesCascades - 1; idx > 0; idx--)
|
||
{
|
||
finalData += KWS_FftWavesDisplace.SampleLevel(sampler_linear_repeat, float3(worldPos.xz * KWS_WavesDomainScaledSizesInv[idx], idx), 0).xyz;
|
||
}
|
||
return finalData * KWS_WavesAreaScale;
|
||
}
|
||
|
||
float3 GetFftWavesDisplacementDynamicWaves(float3 worldPos)
|
||
{
|
||
worldPos += KWS_WaterWorldPosOffset;
|
||
int maxCascadeIdx = KWS_WavesCascades - 1;
|
||
|
||
float3 finalData = 0;
|
||
for (int idx = maxCascadeIdx; idx > 1; idx--)
|
||
{
|
||
finalData += KWS_FftWavesDisplace.SampleLevel(sampler_linear_repeat, float3(worldPos.xz * KWS_WavesDomainScaledSizesInv[idx], idx), 0).xyz * saturate((idx + 0.25) / maxCascadeIdx);
|
||
}
|
||
return finalData * KWS_WavesAreaScale;
|
||
}
|
||
|
||
Texture2DArray KWS_BakedFFT_Lod0;
|
||
Texture2DArray KWS_BakedFFT_Lod1;
|
||
Texture2DArray KWS_BakedFFT_Lod2;
|
||
Texture2DArray KWS_BakedFFT_Lod3;
|
||
|
||
|
||
|
||
|
||
float3 GetFftWavesDisplacement(float3 worldPos, float attenuation = 1)
|
||
{
|
||
//#define KWS_USE_BAKED_OCEAN_WAVES
|
||
|
||
|
||
#ifdef KWS_USE_BAKED_OCEAN_WAVES
|
||
|
||
|
||
worldPos += KWS_WaterWorldPosOffset;
|
||
float distanceToCamera = GetWorldToCameraDistance(worldPos);
|
||
float4 fade4 = KWS_GetFftFade4(distanceToCamera);
|
||
float4 windAttenuation = lerp(attenuation * saturate(1.2 - float4(0.0, 0.2, 0.4, 0.6)), float4(1, 1, 1, 1), attenuation);
|
||
|
||
float3 finalData = 0;
|
||
|
||
float loopTime = 4;
|
||
float frames = 120;
|
||
float time = KWS_ScaledTime % loopTime;
|
||
int frameIndex = ceil(time * (frames / loopTime));
|
||
|
||
float4 packedLod0 = KWS_BakedFFT_Lod0.SampleLevel(sampler_linear_repeat, float3(worldPos.xz * KWS_WavesDomainScaledSizesInv.x, frameIndex), 0);
|
||
float4 packedLod1 = KWS_BakedFFT_Lod1.SampleLevel(sampler_linear_repeat, float3(worldPos.xz * KWS_WavesDomainScaledSizesInv.y, frameIndex), 0);
|
||
float4 packedLod2 = KWS_BakedFFT_Lod2.SampleLevel(sampler_linear_repeat, float3(worldPos.xz * KWS_WavesDomainScaledSizesInv.z, frameIndex), 0);
|
||
float4 packedLod3 = KWS_BakedFFT_Lod3.SampleLevel(sampler_linear_repeat, float3(worldPos.xz * KWS_WavesDomainScaledSizesInv.w, frameIndex), 0);
|
||
|
||
float3 currentLod0 = Unpack_R16G16B16f(packedLod0.xy, 3);
|
||
float3 currentLod1 = Unpack_R16G16B16f(packedLod1.xy, 3);
|
||
float3 currentLod2 = Unpack_R16G16B16f(packedLod2.xy, 3);
|
||
float3 currentLod3 = Unpack_R16G16B16f(packedLod3.xy, 3);
|
||
|
||
finalData += fade4.x * windAttenuation.x * currentLod0;
|
||
finalData += fade4.y * windAttenuation.y * currentLod1;
|
||
finalData += fade4.z * windAttenuation.z * currentLod2;
|
||
finalData += fade4.w * windAttenuation.w * currentLod3;
|
||
|
||
return finalData * KWS_WavesAreaScale;
|
||
|
||
#else
|
||
|
||
worldPos += KWS_WaterWorldPosOffset;
|
||
float distanceToCamera = GetWorldToCameraDistance(worldPos);
|
||
float4 fade4 = KWS_GetFftFade4(distanceToCamera);
|
||
float4 windAttenuation = lerp(attenuation * saturate(1.2 - float4(0.0, 0.2, 0.4, 0.6)), float4(1, 1, 1, 1), attenuation);
|
||
|
||
float3 finalData = 0;
|
||
|
||
finalData += fade4.x * windAttenuation.x * KWS_FftWavesDisplace.SampleLevel(sampler_linear_repeat, float3(worldPos.xz * KWS_WavesDomainScaledSizesInv.x, 0), 0).xyz;
|
||
finalData += fade4.y * windAttenuation.y * KWS_FftWavesDisplace.SampleLevel(sampler_linear_repeat, float3(worldPos.xz * KWS_WavesDomainScaledSizesInv.y, 1), 0).xyz;
|
||
finalData += fade4.z * windAttenuation.z * KWS_FftWavesDisplace.SampleLevel(sampler_linear_repeat, float3(worldPos.xz * KWS_WavesDomainScaledSizesInv.z, 2), 0).xyz;
|
||
finalData += fade4.w * windAttenuation.w * KWS_FftWavesDisplace.SampleLevel(sampler_linear_repeat, float3(worldPos.xz * KWS_WavesDomainScaledSizesInv.w, 3), 0).xyz;
|
||
|
||
return finalData * KWS_WavesAreaScale;
|
||
|
||
#endif
|
||
}
|
||
|
||
|
||
|
||
float GetNoiseMask(float2 uv, float scale, float timeScale)
|
||
{
|
||
uv *= scale;
|
||
float currentTime = KWS_ScaledTime * timeScale;
|
||
//float2 noise1 = float2(SimpleNoise1(uv * 0.005 + currentTime * 0.15), SimpleNoise1(uv * 0.005 - (currentTime * 0.15 + 40)));
|
||
float2 noise2 = float2(SimpleNoise1(uv * 0.026 + currentTime * 0.06), SimpleNoise1(uv * 0.024 - (currentTime * 0.07 + 40)));
|
||
//float animNoise1 = saturate(0.05 + KWS_Pow10(1 - saturate(max(noise1.x, noise1.y) * 0.2)));
|
||
float animNoise2 = saturate(0.1 + KWS_Pow5(1 - saturate(max(noise2.x, noise2.y) * 0.75)));
|
||
return animNoise2;
|
||
}
|
||
|
||
float3 GetFftWavesNormalFoam(float3 worldPos, float attenuation)
|
||
{
|
||
float distanceToCamera = GetWorldToCameraDistance(worldPos);
|
||
float3 finalData = float3(0, 1, 0);
|
||
float foam = 0;
|
||
int idx = KWS_WavesCascades;
|
||
worldPos += KWS_WaterWorldPosOffset;
|
||
|
||
UNITY_UNROLL for (int i = 0; i <= MAX_FFT_WAVES_MAX_CASCADES; i++)
|
||
{
|
||
idx--;
|
||
if (idx < 0) break;
|
||
|
||
float fade = GetFftFade(distanceToCamera, idx, 0.25);
|
||
float windAttenuation = lerp(attenuation * saturate(1.2 - 0.2 * idx), 1, attenuation);
|
||
|
||
fade *= windAttenuation;
|
||
|
||
//if (fade < 0.01) continue;
|
||
float3 data = float3(fade, 1, fade);
|
||
float3 normal = 0;
|
||
|
||
if (idx == 0 || idx == 3) normal = Texture2DArraySampleBicubic(KWS_FftWavesNormal, sampler_linear_repeat, worldPos.xz * KWS_WavesDomainScaledSizesInv[idx], KWS_FftWavesNormal_TexelSize, idx).xyz;
|
||
else normal = KWS_FftWavesNormal.Sample(sampler_KWS_FftWavesNormal, float3(worldPos.xz * KWS_WavesDomainScaledSizesInv[idx], idx)).xyz;
|
||
|
||
data *= normal;
|
||
|
||
foam += data.y;
|
||
data.y = 1;
|
||
finalData = KWS_BlendNormals(finalData, data);
|
||
|
||
}
|
||
|
||
//return finalData;
|
||
return float3(finalData.x, foam, finalData.z);
|
||
}
|
||
|
||
|
||
float GetFftWavesHeight(float3 worldPos, uint iterations)
|
||
{
|
||
float3 invertedDisplacedPosition = worldPos;
|
||
for (uint i = 0; i < iterations; i++)
|
||
{
|
||
float3 displacement = GetFftWavesDisplacementBuoyancy(invertedDisplacedPosition);
|
||
float3 error = (invertedDisplacedPosition + displacement) - worldPos;
|
||
invertedDisplacedPosition -= error;
|
||
}
|
||
|
||
float3 disp = GetFftWavesDisplacement(invertedDisplacedPosition);
|
||
return disp.y;
|
||
}
|
||
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
|
||
|
||
////////////////////////////////////////////// PrePass (Mask/Normal/SSS/VolumeMask/Depth) //////////////////////////////////////////////
|
||
|
||
|
||
//#define WATER_MASK_PASS_UNDERWATER_THRESHOLD 0.35
|
||
#define WATER_VOLUME_PRE_PASS_MAX_VALUE 1000000
|
||
#define WATER_LINE_HEIGHT_ENCODE_VALUE 10000
|
||
|
||
DECLARE_TEXTURE(KWS_WaterPrePassRT0);
|
||
DECLARE_TEXTURE(KWS_WaterPrePassRT1);
|
||
DECLARE_TEXTURE(KWS_WaterDepthRT);
|
||
DECLARE_TEXTURE(KWS_WaterIntersectionHalfLineTensionMaskRT);
|
||
float4 KWS_WaterPrePassRT0_TexelSize;
|
||
float4 KWS_WaterPrePass_RTHandleScale;
|
||
|
||
DECLARE_TEXTURE(KWS_WaterBackfacePrePassRT0);
|
||
DECLARE_TEXTURE(KWS_WaterBackfacePrePassRT1);
|
||
DECLARE_TEXTURE(KWS_WaterBackfaceDepthRT);
|
||
|
||
float4 KWS_WaterBackfacePrePassRT0_TexelSize;
|
||
float4 KWS_WaterBackfacePrePass_RTHandleScale;
|
||
|
||
inline float2 GetWaterPrePassUV(float2 uv)
|
||
{
|
||
uv = GetRTHandleUV(uv, KWS_WaterPrePassRT0_TexelSize.xy, 1.0, KWS_WaterPrePass_RTHandleScale.xy);
|
||
return uv;
|
||
}
|
||
|
||
inline float2 GetWaterBackfacePrePassUV(float2 uv)
|
||
{
|
||
uv = GetRTHandleUV(uv, KWS_WaterBackfacePrePassRT0_TexelSize.xy, 1.0, KWS_WaterBackfacePrePass_RTHandleScale.xy);
|
||
return uv;
|
||
}
|
||
|
||
inline float GetWaterSSS(float2 uv)
|
||
{
|
||
return SAMPLE_TEXTURE_LOD(KWS_WaterPrePassRT0, sampler_linear_clamp, GetWaterPrePassUV(uv), 0).z;
|
||
}
|
||
|
||
inline float3 GetWaterNormals(float2 uv)
|
||
{
|
||
float2 rawNormal = SAMPLE_TEXTURE_LOD(KWS_WaterPrePassRT1, sampler_linear_clamp, GetWaterPrePassUV(uv), 0).xy;
|
||
#ifdef KWS_USE_AQUARIUM_RENDERING
|
||
float2 rawNormalBackface = SAMPLE_TEXTURE_LOD(KWS_WaterBackfacePrePassRT1, sampler_point_clamp, GetWaterBackfacePrePassUV(uv), 0).xy;
|
||
rawNormal += rawNormalBackface;
|
||
#endif
|
||
|
||
return float3(rawNormal.x, 1, rawNormal.y);
|
||
}
|
||
|
||
|
||
inline float GetWaterAquariumBackfaceMask(float2 uv)
|
||
{
|
||
return SAMPLE_TEXTURE_LOD(KWS_WaterBackfacePrePassRT0, sampler_point_clamp, GetWaterBackfacePrePassUV(uv), 0).y;
|
||
}
|
||
|
||
|
||
//inside = 1, surface outside = 0.5, box fringe = 0.1
|
||
inline float GetWaterMaskFast(float2 uv, float2 offset = float2(0, 0))
|
||
{
|
||
return SAMPLE_TEXTURE_LOD(KWS_WaterPrePassRT0, sampler_linear_clamp, GetWaterPrePassUV(uv), 0).y;
|
||
}
|
||
|
||
|
||
//inside = 1, surface outside = 0.5, box fringe = 0.1
|
||
inline float GetWaterMask(float2 uv, float2 offset = float2(0, 0))
|
||
{
|
||
#ifdef KWS_SHARED_API_INCLUDED
|
||
return GetWaterMaskFast(uv);
|
||
#else
|
||
|
||
float4 mask = SAMPLE_TEXTURE_GATHER_GREEN(KWS_WaterPrePassRT0, sampler_linear_clamp, GetWaterPrePassUV(uv) + KWS_WaterPrePassRT0_TexelSize.xy * offset);
|
||
return max(mask.x, max(mask.y, max(mask.z, mask.w)));
|
||
#endif
|
||
|
||
//float mask = SAMPLE_TEXTURE_LOD(KWS_WaterPrePassRT0, sampler_point_clamp, GetWaterPrePassUV(uv), 0).y;
|
||
|
||
//float center = SAMPLE_TEXTURE_LOD(KW_WaterMaskScatterNormals, sampler_point_clamp, GetWaterPrePassUV(uv), 0).x;
|
||
//float up = SAMPLE_TEXTURE_LOD_OFFSET(KW_WaterMaskScatterNormals, sampler_point_clamp, GetWaterPrePassUV(uv), 0, int2(0, 1)).x;
|
||
//float down = SAMPLE_TEXTURE_LOD_OFFSET(KW_WaterMaskScatterNormals, sampler_point_clamp, GetWaterPrePassUV(uv), 0, int2(0, -1)).x;
|
||
//float diff = (up + down) * 0.5 - center;
|
||
|
||
//if((center == 0.0 || center == 1.0) && down == up) return down;
|
||
|
||
//return mask;
|
||
|
||
}
|
||
|
||
|
||
inline float GetUnderwaterMask(float waterMask)
|
||
{
|
||
return waterMask > 0.5;
|
||
}
|
||
|
||
inline bool GetSurfaceMask(float waterMask)
|
||
{
|
||
return abs(waterMask - 0.25) < 0.01;
|
||
}
|
||
|
||
inline bool GetUnderwaterSurfaceMask(float waterMask)
|
||
{
|
||
return abs(waterMask - 0.75) < 0.01;
|
||
}
|
||
|
||
|
||
inline float GetWaterHalfLineTensionMask(float2 uv)
|
||
{
|
||
float intersectionMask = 0;
|
||
float aquariumMask = 0;
|
||
float2 scaledUV = GetWaterPrePassUV(uv);
|
||
|
||
#ifdef KWS_IS_CAMERA_PARTIAL_UNDERWATER
|
||
intersectionMask = SAMPLE_TEXTURE_LOD(KWS_WaterIntersectionHalfLineTensionMaskRT, sampler_linear_clamp, scaledUV, 0).x;
|
||
intersectionMask *= 1.4;
|
||
if (intersectionMask >= 0.99) intersectionMask = saturate((1.2 - intersectionMask) * 5);
|
||
#endif
|
||
#ifdef KWS_USE_AQUARIUM_RENDERING
|
||
aquariumMask = SAMPLE_TEXTURE_LOD(KWS_WaterPrePassRT0, sampler_linear_clamp, scaledUV, 0).w;
|
||
intersectionMask = max(intersectionMask, aquariumMask);
|
||
#endif
|
||
|
||
return intersectionMask;
|
||
}
|
||
|
||
|
||
inline float GetWaterDepth(float2 uv)
|
||
{
|
||
return SAMPLE_TEXTURE_LOD(KWS_WaterDepthRT, sampler_linear_clamp, GetWaterPrePassUV(uv), 0).x;
|
||
}
|
||
|
||
inline float GetWaterDepthFiltered(float2 uv)
|
||
{
|
||
float4 depth = SAMPLE_TEXTURE_GATHER(KWS_WaterDepthRT, sampler_linear_clamp, GetWaterPrePassUV(uv));
|
||
return KWS_MIN(depth);
|
||
}
|
||
|
||
|
||
inline float GetWaterBackfaceDepth(float2 uv)
|
||
{
|
||
return SAMPLE_TEXTURE_LOD(KWS_WaterBackfaceDepthRT, sampler_linear_clamp, GetWaterBackfacePrePassUV(uv), 0).x;
|
||
}
|
||
|
||
inline uint GetWaterLocalZonesTransparent(float2 uv)
|
||
{
|
||
return SAMPLE_TEXTURE_LOD(KWS_WaterPrePassRT0, sampler_linear_clamp, GetWaterPrePassUV(uv), 0).x * 100.0;
|
||
}
|
||
|
||
//Front depth (x), Back depth (y)
|
||
inline float2 GetWaterVolumeDepth(float2 uv, float surfaceZ, float sceneZ, float waterMask)
|
||
{
|
||
float2 volumeDepth = 0;
|
||
|
||
volumeDepth.x = surfaceZ;
|
||
volumeDepth.y = sceneZ;
|
||
|
||
#if KWS_USE_AQUARIUM_RENDERING
|
||
volumeDepth.y = max(volumeDepth.y, GetWaterBackfaceDepth(uv));
|
||
#endif
|
||
|
||
bool underwaterMask = GetUnderwaterMask(waterMask);
|
||
volumeDepth.y = lerp(volumeDepth.y, max(volumeDepth.x, sceneZ), underwaterMask);
|
||
volumeDepth.x = lerp(volumeDepth.x, 1, underwaterMask);
|
||
|
||
if (volumeDepth.x < sceneZ) volumeDepth.x = 0;
|
||
|
||
return volumeDepth;
|
||
}
|
||
|
||
//Front depth (x), Back depth (y)
|
||
inline float2 GetWaterVolumeDepth(float2 uv, float sceneZ, float waterMask)
|
||
{
|
||
float2 volumeDepth = 0;
|
||
|
||
volumeDepth.x = GetWaterDepth(uv).x;
|
||
volumeDepth.y = sceneZ;
|
||
|
||
#if KWS_USE_AQUARIUM_RENDERING
|
||
volumeDepth.y = max(volumeDepth.y, GetWaterBackfaceDepth(uv));
|
||
#endif
|
||
|
||
bool underwaterMask = GetUnderwaterMask(waterMask);
|
||
volumeDepth.y = lerp(volumeDepth.y, max(volumeDepth.x, sceneZ), underwaterMask);
|
||
volumeDepth.x = lerp(volumeDepth.x, 1, underwaterMask);
|
||
|
||
if (volumeDepth.x < sceneZ) volumeDepth.x = 0;
|
||
|
||
return volumeDepth;
|
||
}
|
||
|
||
inline float GetBoxExtrude(float3 pos, float3x3 rotationMatrix, float3 size)
|
||
{
|
||
float3 rotatedPos = mul(rotationMatrix, pos).xyz;
|
||
float3 d = abs(rotatedPos) - size;
|
||
return length(max(d, 0)) + KWS_MAX(min(d, 0));
|
||
}
|
||
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
|
||
|
||
|
||
////////////////////////////////////////////// VolumetricLighting_Pass //////////////////////////////////////////////
|
||
|
||
DECLARE_TEXTURE(KWS_VolumetricLightRT);
|
||
DECLARE_TEXTURE(KWS_VolumetricLightAdditionalDataRT);
|
||
DECLARE_TEXTURE(KWS_VolumetricLightSurfaceRT);
|
||
|
||
float4 KWS_VolumetricLightRT_TexelSize;
|
||
float4 KWS_VolumetricLight_RTHandleScale;
|
||
|
||
DECLARE_TEXTURE(KWS_VolumetricLightRT_Last);
|
||
float4 KWS_VolumetricLightRT_Last_TexelSize;
|
||
float4 KWS_VolumetricLightRT_Last_RTHandleScale;
|
||
|
||
struct VolumetricLightAdditionalData
|
||
{
|
||
half SurfaceDirShadow;
|
||
half SceneDirShadow;
|
||
half AdditionalLightsAttenuation;
|
||
};
|
||
|
||
|
||
|
||
inline float GetMaxRayDistanceRelativeToTransparent(float transparent)
|
||
{
|
||
return min(KWS_MAX_TRANSPARENT, transparent * 1.5);
|
||
}
|
||
|
||
|
||
inline half4 GetVolumetricLight(float2 uv)
|
||
{
|
||
return SAMPLE_TEXTURE_LOD(KWS_VolumetricLightRT, sampler_linear_clamp, saturate(uv), 0);
|
||
}
|
||
|
||
//(R) surface dir shadow, (G) scene dir shadow, (B) additional lights attenuation
|
||
inline VolumetricLightAdditionalData GetVolumetricLightAdditionalData(float2 uv)
|
||
{
|
||
float3 rawData = SAMPLE_TEXTURE_LOD(KWS_VolumetricLightAdditionalDataRT, sampler_linear_clamp, saturate(uv), 0).xyz;
|
||
#if defined(KWS_USE_DYNAMIC_WAVES)
|
||
float4 shadowFix = SAMPLE_TEXTURE_GATHER(KWS_VolumetricLightAdditionalDataRT, sampler_linear_clamp, saturate(uv));
|
||
rawData.x = rawData.x * shadowFix.x * shadowFix.y * shadowFix.z * shadowFix.w;
|
||
#endif
|
||
|
||
|
||
VolumetricLightAdditionalData volumeData;
|
||
volumeData.SurfaceDirShadow = rawData.x;
|
||
volumeData.SceneDirShadow = rawData.y;
|
||
volumeData.AdditionalLightsAttenuation = rawData.z;
|
||
return volumeData;
|
||
}
|
||
|
||
|
||
inline float3 GetVolumetricSurfaceLight(float2 uv)
|
||
{
|
||
float3 surfaceLight = SAMPLE_TEXTURE_LOD(KWS_VolumetricLightSurfaceRT, sampler_linear_clamp, saturate(uv), 0).xyz;
|
||
if(surfaceLight.r < 0.00001) return GetAmbientColor(GetExposure());
|
||
else return surfaceLight;
|
||
}
|
||
|
||
inline float GetVolumeLightInDepthTransmitance(float waterSurfaceHeight, float transparent)
|
||
{
|
||
float distanceToWaterSurface = waterSurfaceHeight - _WorldSpaceCameraPos.y - 1;
|
||
float lightInDepthTransmitance = saturate(exp2(-0.5 * distanceToWaterSurface / max(2, transparent)) * 1.1 - 0.1);
|
||
|
||
return lightInDepthTransmitance;
|
||
}
|
||
|
||
|
||
inline float GetVolumeLightSunAngleAttenuation(float3 lightDir, float3 normal = float3(0, 1, 0))
|
||
{
|
||
float dotVal = dot(lightDir, normal);
|
||
return smoothstep(-0.25, 1.0, dotVal);
|
||
//return saturate(dot(lightDir, normal));
|
||
|
||
}
|
||
|
||
inline half3 GetVolumetricSurfaceLight(float4 volumeScattering, float3 normal, float exposure)
|
||
{
|
||
float3 ambient = GetAmbientColor(exposure);
|
||
float3 dirLight = GetVolumeLightSunAngleAttenuation(GetMainLightDir(), normal) * GetMainLightColor(exposure);
|
||
|
||
return (ambient + dirLight * volumeScattering.a + volumeScattering.rgb);
|
||
}
|
||
|
||
float4 ComputeAbsorbtion(float transparent, float3 waterColor, float rayLength)
|
||
{
|
||
float dyeOverrideFactor = dot(waterColor, 0.33);
|
||
float3 absorbtionColor = lerp(1 - waterColor, float3(1.0, 0.12, 0.02), dyeOverrideFactor);
|
||
float absorbtionMultiplier = lerp(0.2, 0.1, saturate((transparent - KWS_MAX_TRANSPARENT) / KWS_MAX_TRANSPARENT));
|
||
|
||
float3 finalAbsorbtion = max(float3(0.0005, 0.001, 0.025), exp2(-KWS_VOLUME_LIGHT_ABSORBTION_FACTOR * pow(rayLength, 1.5) * absorbtionColor * absorbtionMultiplier));
|
||
|
||
rayLength = min(rayLength, min(KWS_MAX_TRANSPARENT, transparent));
|
||
float extintionIntegralApproximationCoeff = KWS_Pow2(transparent * 0.2);
|
||
|
||
float extinction = 1 - saturate(exp2(-rayLength / extintionIntegralApproximationCoeff + KWS_VOLUME_LIGHT_TRANSMITANCE_NEAR_OFFSET_FACTOR));
|
||
|
||
return saturate(float4(finalAbsorbtion, extinction));
|
||
}
|
||
|
||
inline half4 GetVolumetricLightWithAbsorbtion(float2 uv, float2 refractionUV, float transparent, float3 tubidityColor, float3 waterColor, float3 sceneColor, float2 volumeDepth, float exposure, float3 sceneColorAdditiveAlbedo)
|
||
{
|
||
float3 frontPos = GetWorldSpacePositionFromDepth(refractionUV, volumeDepth.x);
|
||
float3 backPos = GetWorldSpacePositionFromDepth(refractionUV, volumeDepth.y);
|
||
float rayLength = length(backPos - frontPos);
|
||
if (volumeDepth.x == 0) rayLength = 0.1;
|
||
|
||
float4 absorbtion = ComputeAbsorbtion(transparent, waterColor, rayLength);
|
||
|
||
float waterSurfaceShadow = 1;
|
||
half sceneAttenuation = GetVolumeLightInDepthTransmitance(KWS_WaterLevel, transparent);
|
||
|
||
#ifdef KWS_USE_VOLUMETRIC_LIGHT
|
||
float4 scattering = GetVolumetricLight(refractionUV);
|
||
//float4 scatteringWithOffset = GetVolumetricLight(uv);
|
||
//if ((scattering.x + scattering.y + scattering.z) <= 0.1) scattering = scatteringWithOffset;
|
||
|
||
VolumetricLightAdditionalData volumeLightData = GetVolumetricLightAdditionalData(uv);
|
||
|
||
sceneAttenuation = max(sceneAttenuation, volumeLightData.AdditionalLightsAttenuation);
|
||
waterSurfaceShadow = volumeLightData.SurfaceDirShadow;
|
||
//absorbtion.a = scattering.a;
|
||
#else
|
||
float phaseG = GetVolumeLightSunAngleAttenuation(GetMainLightDir());
|
||
float3 sceneLight = 0.5 * GetAmbientColor(exposure) + GetMainLightColor(exposure) * phaseG;
|
||
float4 scattering = half4(0.5 * tubidityColor * saturate(sceneLight), 1.0);
|
||
#endif
|
||
|
||
sceneColor *= sceneAttenuation;
|
||
|
||
#ifdef KWS_SHARED_API_INCLUDED
|
||
float3 albedo = sceneColorAdditiveAlbedo * dot(scattering.xyz, 0.33);
|
||
float3 finalColor = lerp(absorbtion.rgb * sceneColor + clamp(albedo, 0, 2), scattering.xyz, absorbtion.a);
|
||
#else
|
||
float3 finalColor = lerp(absorbtion.rgb * sceneColor, scattering.xyz, absorbtion.a);
|
||
#endif
|
||
|
||
return float4(finalColor * sceneAttenuation, waterSurfaceShadow);
|
||
}
|
||
|
||
|
||
|
||
inline half4 GetVolumetricLightWithAbsorbtionByDistance(float2 uv, float2 refractionUV, float transparent, float3 tubidityColor, float3 dyeColor, float3 sceneColor, float rayLength, float exposure, float3 sceneColorAdditiveAlbedo)
|
||
{
|
||
float4 absorbtion = ComputeAbsorbtion(transparent, dyeColor, rayLength);
|
||
|
||
#ifdef KWS_USE_VOLUMETRIC_LIGHT
|
||
float4 scattering = GetVolumetricLight(refractionUV);
|
||
//float4 scatteringWithOffset = GetVolumetricLight(uv);
|
||
//if ((scattering.x + scattering.y + scattering.z) <= 0.1) scattering = scatteringWithOffset;
|
||
|
||
//absorbtion.a = scattering.a;
|
||
#else
|
||
float phaseG = GetVolumeLightSunAngleAttenuation(GetMainLightDir());
|
||
float3 sceneLight = 0.5 * GetAmbientColor(exposure) + GetMainLightColor(exposure) * phaseG;
|
||
float4 scattering = half4(0.5 * tubidityColor * saturate(sceneLight), 1.0);
|
||
#endif
|
||
|
||
#ifdef KWS_SHARED_API_INCLUDED
|
||
float3 albedo = sceneColorAdditiveAlbedo * dot(scattering.xyz, 0.33);
|
||
float3 finalColor = lerp(absorbtion.rgb * sceneColor + clamp(albedo, 0, 2), scattering.xyz, absorbtion.a);
|
||
#else
|
||
float3 finalColor = lerp(absorbtion.rgb * sceneColor, scattering.xyz, absorbtion.a);
|
||
#endif
|
||
|
||
return float4(finalColor, absorbtion.a);
|
||
}
|
||
|
||
|
||
inline half3 GetSurfaceLightWithAbsorbtion(float2 uv, float transparent, float3 tubidityColor, float3 dyeColor, float exposure)
|
||
{
|
||
float dyeOverrideFactor = dot(dyeColor, 0.33);
|
||
float3 absorbtionColor = lerp(1 - dyeColor, float3(1.0, 0.13, 0.02), dyeOverrideFactor);
|
||
float absorbtionMultiplier = lerp(1, 0.0, saturate((transparent) / KWS_MAX_TRANSPARENT));
|
||
|
||
float extinction = 0;
|
||
|
||
float3 finalAbsorbtion = absorbtionColor;
|
||
|
||
float phaseG = GetVolumeLightSunAngleAttenuation(GetMainLightDir());
|
||
float3 sceneLight = 0.5 * GetAmbientColor(exposure) + GetMainLightColor(exposure) * phaseG;
|
||
float4 scattering = half4(0.5 * tubidityColor * saturate(sceneLight), 1.0);
|
||
|
||
float3 finalColor = lerp(finalAbsorbtion * absorbtionMultiplier, scattering.xyz, 0.5);
|
||
|
||
return finalColor;
|
||
}
|
||
|
||
inline half3 GetSurfaceLightWithAbsorbtionByDistance(float2 uv, float transparent, float3 tubidityColor, float3 dyeColor, float rayLength, float exposure)
|
||
{
|
||
float dyeOverrideFactor = dot(dyeColor, 0.33);
|
||
float3 absorbtionColor = lerp(1 - dyeColor, float3(1.0, 0.13, 0.02), dyeOverrideFactor);
|
||
float absorbtionMultiplier = lerp(1, 0.0, saturate((transparent) / KWS_MAX_TRANSPARENT));
|
||
|
||
float extinction = 1 - saturate(exp2(-rayLength));
|
||
|
||
float3 finalAbsorbtion = max(float3(0.0005, 0.001, 0.025), exp2(-rayLength * absorbtionColor));
|
||
|
||
float phaseG = GetVolumeLightSunAngleAttenuation(GetMainLightDir());
|
||
float3 sceneLight = 0.5 * GetAmbientColor(exposure) + GetMainLightColor(exposure) * phaseG;
|
||
float4 scattering = half4(0.5 * tubidityColor * saturate(sceneLight), 1.0);
|
||
|
||
float3 finalColor = lerp(finalAbsorbtion * absorbtionMultiplier, scattering.xyz, extinction);
|
||
|
||
return finalColor;
|
||
}
|
||
|
||
|
||
inline half4 GetVolumetricLightLastFrame(float2 uv)
|
||
{
|
||
//float2 scaledUV = GetRTHandleUV(uv, KWS_VolumetricLightRT_TexelSize.xy, 1.0, KWS_VolumetricLight_RTHandleScale.xy);
|
||
//scaledUV += KWS_VolumetricLightRT_TexelSize.xy * 0.5;
|
||
return SAMPLE_TEXTURE_LOD(KWS_VolumetricLightRT_Last, sampler_point_clamp, uv, 0);
|
||
}
|
||
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
////////////////////////////////////////////// ScreenSpaceReflection_Pass //////////////////////////////////////////////
|
||
DECLARE_TEXTURE(KWS_ScreenSpaceReflectionRT);
|
||
float4 KWS_ScreenSpaceReflectionRT_TexelSize;
|
||
float4 KWS_ScreenSpaceReflection_RTHandleScale;
|
||
#define KWS_ScreenSpaceReflectionMaxMip 4
|
||
|
||
inline float2 GetScreenSpaceReflectionNormalizedUV(float2 uv)
|
||
{
|
||
uv = GetRTHandleUV(uv, KWS_ScreenSpaceReflectionRT_TexelSize.xy, 0.5, KWS_ScreenSpaceReflection_RTHandleScale.xy);
|
||
//uv -= KWS_ScreenSpaceReflectionRT_TexelSize.xy * 0.5;
|
||
return uv;
|
||
//return clamp(uv, 0.001, 0.999) * KWS_ScreenSpaceReflection_RTHandleScale.xy;
|
||
|
||
}
|
||
|
||
inline half4 GetScreenSpaceReflection(float2 uv, float3 worldPos)
|
||
{
|
||
float2 ssrUV = GetScreenSpaceReflectionNormalizedUV(uv);
|
||
float mipLevel = CalcMipLevel(ssrUV * KWS_ScreenSpaceReflectionRT_TexelSize.zw);
|
||
|
||
float distance = length(worldPos.xz - GetCameraAbsolutePosition().xz);
|
||
float anisoScaleRelativeToDistance = saturate(distance * 0.05);
|
||
|
||
float lod = min(mipLevel, KWS_ScreenSpaceReflectionMaxMip);
|
||
//lod = anisoScaleRelativeToDistance * 2;
|
||
|
||
ssrUV.y -= KWS_ScreenSpaceReflectionRT_TexelSize.y * 2;
|
||
float4 res = SAMPLE_TEXTURE_LOD(KWS_ScreenSpaceReflectionRT, sampler_trilinear_clamp, ssrUV, lod);
|
||
//res.a = saturate(res.a); //I use negative alpha to minimize edge bilinear interpolation artifacts.
|
||
return res;
|
||
}
|
||
|
||
float KWS_ScreenSpaceBordersStretching;
|
||
inline half4 GetScreenSpaceReflectionWithStretchingMask(float2 uv, float3 worldPos)
|
||
{
|
||
#if defined(STEREO_INSTANCING_ON)
|
||
uv -= mul((float2x2)UNITY_MATRIX_V, float2(0, KWS_ReflectionClipOffset)).xy;
|
||
#else
|
||
uv.y -= KWS_ReflectionClipOffset;
|
||
#endif
|
||
|
||
float AngleStretch = max(0.25, saturate(-KWS_CameraForward.y * 1.5));
|
||
float ScreenStretch = saturate(abs(uv.x * 2 - 1) - 0.8);
|
||
float uvOffset = -AngleStretch * ScreenStretch * KWS_ScreenSpaceBordersStretching * 10;
|
||
uv.x = uv.x * (1 + uvOffset * 2) - uvOffset;
|
||
//float stretchingMask = 1 - abs(refl_uv.x * 2 - 1);
|
||
//refl_uv.x = lerp(refl_uv.x * (1 - Test4.x * 2) + Test4.x, refl_uv.x, AngleStretch * ScreenStretch);
|
||
return GetScreenSpaceReflection(uv, worldPos);
|
||
}
|
||
|
||
|
||
float GetAnisoScaleRelativeToWind(float windSpeed)
|
||
{
|
||
float normalizedWind = saturate((windSpeed) / 10.0);
|
||
float curved = 1.0 - pow(1.0 - normalizedWind, KWS_AnisoWindCurvePower);
|
||
return (curved) * KWS_AnisoReflectionsScale;
|
||
}
|
||
|
||
float2 GetScreenSpaceReflectionUV(float3 reflDir, float2 orthoUV)
|
||
{
|
||
UNITY_BRANCH
|
||
if (unity_OrthoParams.w == 1.0) return orthoUV;
|
||
else
|
||
{
|
||
reflDir.y = -reflDir.y;
|
||
float4 projected = mul(UNITY_MATRIX_VP, float4(reflDir, 0));
|
||
float2 uv = (projected.xy / projected.w) * 0.5f + 0.5f;
|
||
|
||
#ifdef UNITY_UV_STARTS_AT_TOP
|
||
uv.y = 1 - uv.y;
|
||
#endif
|
||
|
||
return uv;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
////////////////////////////////////////////// Planar Reflection //////////////////////////////////////////////////////////
|
||
DECLARE_TEXTURE(KWS_PlanarReflectionRT);
|
||
int KWS_PlanarReflectionInstanceID;
|
||
float4 KWS_PlanarReflectionRT_TexelSize;
|
||
TextureCube KWS_CubemapReflectionRT;
|
||
|
||
#define KWS_PlanarReflectionMaxMip 4
|
||
|
||
inline half3 GetPlanarReflection(float2 refl_uv)
|
||
{
|
||
float mipLevel = CalcMipLevel(refl_uv * KWS_PlanarReflectionRT_TexelSize.zw);
|
||
float lod = min(mipLevel, KWS_PlanarReflectionMaxMip);
|
||
return SAMPLE_TEXTURE_LOD(KWS_PlanarReflectionRT, sampler_trilinear_clamp, refl_uv, lod).xyz;
|
||
}
|
||
|
||
inline half3 GetPlanarReflectionRaw(float2 refl_uv)
|
||
{
|
||
return SAMPLE_TEXTURE_LOD(KWS_PlanarReflectionRT, sampler_trilinear_clamp, refl_uv, 0).xyz;
|
||
}
|
||
|
||
inline half3 GetPlanarReflectionWithClipOffset(float2 refl_uv)
|
||
{
|
||
#if defined(STEREO_INSTANCING_ON)
|
||
refl_uv -= mul((float2x2)UNITY_MATRIX_V, float2(0, KWS_ReflectionClipOffset)).xy;
|
||
#else
|
||
refl_uv.y -= KWS_ReflectionClipOffset;
|
||
#endif
|
||
return GetPlanarReflection(refl_uv);
|
||
}
|
||
|
||
|
||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
|
||
|
||
////////////////////////////////////////////// Reflection Effects Pass //////////////////////////////////////////////////////////
|
||
|
||
float Fresnel_IOR(float3 viewDir, float3 normal, float ior)
|
||
{
|
||
float cosi = clamp(-1, 1, dot(viewDir, normal));
|
||
float etai = 1, etat = ior;
|
||
if (cosi > 0)
|
||
{
|
||
float temp = etat;
|
||
etat = etai;
|
||
etai = temp;
|
||
}
|
||
|
||
float sint = etai / etat * sqrt(max(0.f, 1 - cosi * cosi));
|
||
|
||
if (sint >= 1)
|
||
{
|
||
return 1;
|
||
}
|
||
else
|
||
{
|
||
float cost = sqrt(max(0.f, 1 - sint * sint));
|
||
cosi = abs(cosi);
|
||
float Rs = ((etat * cosi) - (etai * cost)) / ((etat * cosi) + (etai * cost));
|
||
float Rp = ((etai * cosi) - (etat * cost)) / ((etai * cosi) + (etat * cost));
|
||
return (Rs * Rs + Rp * Rp) / 2;
|
||
}
|
||
// As a consequence of the conservation of energy, transmittance is given by:
|
||
// kt = 1 - kr;
|
||
|
||
}
|
||
|
||
inline half SelfSmithJointGGXVisibilityTerm(half NdotL, half NdotV, half roughness)
|
||
{
|
||
half a = roughness;
|
||
half lambdaV = NdotL * (NdotV * (1 - a) + a);
|
||
half lambdaL = NdotV * (NdotL * (1 - a) + a);
|
||
|
||
return 0.5f / (lambdaV + lambdaL + 1e-5f);
|
||
}
|
||
|
||
|
||
inline half SelfGGXTerm(half NdotH, half roughness)
|
||
{
|
||
half a2 = roughness * roughness;
|
||
half d = (NdotH * a2 - NdotH) * NdotH + 1.0f; // 2 mad
|
||
return 0.31830988618f * a2 / (d * d + 1e-7f); // This function is not intended to be running on Mobile,
|
||
// therefore epsilon is smaller than what can be represented by half
|
||
|
||
}
|
||
|
||
inline half ComputeSpecular(half nl, half nv, half nh, half viewDistNormalized, half smoothness)
|
||
{
|
||
half V = SelfSmithJointGGXVisibilityTerm(nl, nv, smoothness);
|
||
half D = SelfGGXTerm(nh, viewDistNormalized * 0.1 + smoothness);
|
||
|
||
half specularTerm = V * D;
|
||
specularTerm = max(0, specularTerm * nl * KWS_SunStrength);
|
||
|
||
return specularTerm;
|
||
}
|
||
|
||
|
||
|
||
float ComputeWaterFresnel(float3 normal, float3 viewDir, float minValue = 0.05)
|
||
{
|
||
float x = 1 - saturate(dot(normal, viewDir));
|
||
return minValue + (1 - minValue) * x * x * x * x ; //fresnel aproximation http://wiki.nuaj.net/images/thumb/1/16/Fresnel.jpg/800px-Fresnel.jpg
|
||
|
||
}
|
||
|
||
half3 ComputeSSS(float2 screenUV, float sssMask, half3 underwaterColor, half shadowMask, half transparent)
|
||
{
|
||
float3 sssColor = underwaterColor;
|
||
return sssMask * shadowMask * sssColor * 1;
|
||
}
|
||
|
||
half3 ComputeSunlight(half3 normal, half3 viewDir, float3 lightDir, float3 lightColor, half shadowMask, float viewDist, float waterFarDistance, half transparent)
|
||
{
|
||
half3 halfDir = normalize(lightDir + viewDir);
|
||
half nh = saturate(dot(normal, halfDir));
|
||
half nl = saturate(dot(normal, lightDir));
|
||
half lh = saturate(dot(lightDir, halfDir));
|
||
half fresnel = saturate(dot(normal, viewDir));
|
||
|
||
float viewDistNormalized = saturate(viewDist / (waterFarDistance * 2));
|
||
half3 specular = ComputeSpecular(nl, fresnel, nh, viewDistNormalized, KWS_SunCloudiness);
|
||
specular = clamp(specular * 10 - 2.5 * saturate(1 - KWS_SunCloudiness * 10), 0, KWS_SunMaxValue);
|
||
//half sunset = saturate(0.01 + dot(lightDir, float3(0, 1, 0))) * 30;
|
||
|
||
return shadowMask * specular * lightColor;
|
||
}
|
||
|
||
|
||
inline half3 ApplyShorelineWavesReflectionFix(float3 reflDir, half3 reflection, half3 underwaterColor)
|
||
{
|
||
float r = 1 - saturate(dot(reflDir, float3(0, 1, 0)));
|
||
return lerp(reflection, max(underwaterColor, reflection), KWS_Pow5(r));
|
||
}
|
||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
|
||
|
||
|
||
|
||
////////////////////////////////////////////// Caustic_Pass //////////////////////////////////////////////////////////
|
||
Texture2DArray KWS_CausticRTArray;
|
||
float4 KWS_CausticRTArray_TexelSize;
|
||
float KWS_CaustisDispersionStrength;
|
||
|
||
inline float3 GetCausticSlice(float2 uv, uint causticSlice)
|
||
{
|
||
float3 caustic = 1;
|
||
#ifdef USE_DISPERSION
|
||
float2 offset = KWS_CausticRTArray_TexelSize.x * KWS_CaustisDispersionStrength;
|
||
caustic.x = KWS_CausticRTArray.Sample(sampler_linear_repeat, float3(uv - offset, causticSlice)).x;
|
||
caustic.y = KWS_CausticRTArray.Sample(sampler_linear_repeat, float3(uv, causticSlice)).x;
|
||
caustic.z = KWS_CausticRTArray.Sample(sampler_linear_repeat, float3(uv + offset, causticSlice)).x;
|
||
#else
|
||
caustic = KWS_CausticRTArray.Sample(sampler_trilinear_repeat, float3(uv, causticSlice)).x;
|
||
#endif
|
||
|
||
return caustic;
|
||
}
|
||
|
||
inline half GetCausticOceanLod(float2 uv, uint causticSlice, float lod)
|
||
{
|
||
return KWS_CausticRTArray.SampleLevel(sampler_linear_repeat, float3(uv, causticSlice), lod).x;
|
||
}
|
||
|
||
inline half GetCausticDynamicWavesZoneLod0(float2 uv, float lod)
|
||
{
|
||
return KWS_CausticFrameLod0.SampleLevel(sampler_linear_repeat, uv, lod).x;
|
||
}
|
||
|
||
inline half GetCausticDynamicWavesZoneLod1(float2 uv, float lod)
|
||
{
|
||
return KWS_CausticFrameLod0.SampleLevel(sampler_linear_repeat, uv, lod).x;
|
||
}
|
||
|
||
float hash21(float2 p){
|
||
p = frac(p*float2(123.34, 345.45));
|
||
p += dot(p, p+34.345);
|
||
return frac(p.x*p.y);
|
||
}
|
||
float valNoise(float2 p){ // p в клеточных координатах
|
||
float2 i = floor(p), f = frac(p);
|
||
float a = hash21(i);
|
||
float b = hash21(i + float2(1,0));
|
||
float c = hash21(i + float2(0,1));
|
||
float d = hash21(i + float2(1,1));
|
||
float2 u = f*f*(3.0-2.0*f); // сглаженная интерполяция
|
||
return lerp(lerp(a,b,u.x), lerp(c,d,u.x), u.y);
|
||
}
|
||
|
||
inline half3 GetOceanCaustic(uint2 pixels, float2 causticUV, float waterDepth)
|
||
{
|
||
float3 domainSizes = float3(2.5, 10, 40.0);
|
||
float3 cascadeDepths = float3(2.5, 10, 40.0);
|
||
|
||
float noise = InterleavedGradientNoiseStatic(pixels);
|
||
float depthJittered = waterDepth + noise * 0.5;
|
||
|
||
int cascadeIdx = 0;
|
||
if (depthJittered > cascadeDepths.x) cascadeIdx = 1;
|
||
|
||
float2 uvScaled = causticUV / domainSizes[cascadeIdx];
|
||
float2 gradx = ddx(causticUV) / domainSizes[cascadeIdx];
|
||
float2 grady = ddy(causticUV) / domainSizes[cascadeIdx];
|
||
|
||
float4 causticData = Tex2DArrayStochastic(KWS_CausticRTArray, sampler_linear_repeat, uvScaled, gradx, grady, cascadeIdx);
|
||
float3 caustic = causticData.xyz - KWS_CAUSTIC_MULTIPLIER * 0.25;
|
||
caustic = lerp(caustic.xxx, caustic.xyz, KWS_UseCausticDispersion);
|
||
|
||
caustic *= saturate(waterDepth * waterDepth);
|
||
|
||
float3 dispersionCaustic = clamp(caustic * KWS_CausticStrength * 5, lerp(0, -1, causticData.w).xxx, 10);
|
||
float simpleCaustic = caustic.x * lerp(1, KWS_CausticStrength, saturate(caustic.x*1000)) * 5;
|
||
|
||
return lerp(simpleCaustic.xxx, dispersionCaustic, KWS_UseCausticDispersion);
|
||
}
|
||
|
||
inline half3 GetDynamicWavesZoneCaustic(float2 causticUV, float waterDepth, float2 flowDirection, float dynamicWavesHeight, float speedMultiplier, float noiseMask)
|
||
{
|
||
float2 causticFlow = flowDirection * 0.8;
|
||
|
||
float3 caustic0 = Texture2DSampleFlowmapJump(KWS_CausticFrameLod0, sampler_linear_repeat, (causticUV / 4) + flowDirection * flowDirection * 0.5, causticFlow, KWS_ScaledTime * 1.0 * speedMultiplier * 2, 1.0).xyz;
|
||
float3 caustic1 = Texture2DSampleFlowmapJump(KWS_CausticFrameLod1, sampler_linear_repeat, (causticUV / 6) + flowDirection * flowDirection * 0.5, causticFlow, KWS_ScaledTime * 1.0 * speedMultiplier * 1, 1.0).xyz - KWS_CAUSTIC_MULTIPLIER * 0.25;
|
||
float3 caustic = (lerp(caustic0.xyz, caustic1.xyz, saturate(KWS_Pow3(waterDepth * 0.25))));
|
||
|
||
float causticSignMask = saturate(caustic.x * 1000);
|
||
|
||
caustic *= saturate(waterDepth * waterDepth) * (0.5 + saturate(dynamicWavesHeight * 4));
|
||
caustic *= lerp(1, KWS_CausticStrength, causticSignMask) * 5;
|
||
caustic *= lerp(noiseMask, saturate(noiseMask + 0.2), saturate(waterDepth * 0.1));
|
||
|
||
return caustic;
|
||
}
|
||
|
||
|
||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
|
||
////////////////////////////////////////////// Flowmap_Pass /////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
|
||
////////////////////////////////////////////// Otrho depth //////////////////////////////////////////////////////////
|
||
Texture2D KWS_WaterOrthoDepthRT;
|
||
Texture2D KWS_WaterOrthoDepthSDF;
|
||
Texture2D KWS_WaterOrthoDepthBackfaceRT;
|
||
|
||
float3 KWS_OrthoDepthPos;
|
||
float4 KWS_OrthoDepthNearFarSize;
|
||
float4x4 KWS_OrthoDepthCameraMatrix;
|
||
float4 KWS_WaterOrthoDepthRT_TexelSize;
|
||
float4 KWS_WaterOrthoDepthSDF_TexelSize;
|
||
|
||
float4 ReconstructWaterOrthoDepthPos(float3 worldPos)
|
||
{
|
||
return mul(KWS_OrthoDepthCameraMatrix, float4(worldPos, 1));
|
||
}
|
||
|
||
float2 GetWaterOrthoDepthUV(float3 worldPos)
|
||
{
|
||
return (worldPos.xz - KWS_OrthoDepthPos.xz) / KWS_OrthoDepthNearFarSize.zw + 0.5;
|
||
}
|
||
|
||
float GetWaterOrthoDepth(float2 uv)
|
||
{
|
||
float cameraHeight = KWS_OrthoDepthNearFarSize.x;
|
||
float far = KWS_OrthoDepthNearFarSize.y;
|
||
float terrainDepth = KWS_WaterOrthoDepthRT.SampleLevel(sampler_linear_clamp, uv, 0).r;
|
||
|
||
float worldDepth = cameraHeight - (1.0 - terrainDepth) * far;
|
||
return worldDepth;
|
||
}
|
||
|
||
//float GetWaterOrthoDepthBicubic(float2 uv)
|
||
//{
|
||
// float cameraHeight = KWS_OrthoDepthNearFarSize.x;
|
||
// float far = KWS_OrthoDepthNearFarSize.y;
|
||
// float terrainDepth = KWS_WaterOrthoDepthRT.SampleLevel(sampler_linear_clamp, uv, 0).r;
|
||
|
||
// float worldDepth = cameraHeight - (1.0 - terrainDepth) * far;
|
||
// return worldDepth;
|
||
//}
|
||
|
||
|
||
float GetWaterOrthoDepthSDF(float2 uv)
|
||
{
|
||
//if (IsOutsideUvBorders(uv)) return 0;
|
||
return KWS_WaterOrthoDepthSDF.SampleLevel(sampler_linear_clamp, uv, 0).x;
|
||
}
|
||
|
||
|
||
float GetWaterOrthoDepth(float3 worldPos)
|
||
{
|
||
float2 uv = GetWaterOrthoDepthUV(worldPos);
|
||
return GetWaterOrthoDepth(uv);
|
||
}
|
||
|
||
float GetWaterOrthoDepthSDF(float3 worldPos)
|
||
{
|
||
float2 uv = GetWaterOrthoDepthUV(worldPos);
|
||
return GetWaterOrthoDepthSDF(uv);
|
||
}
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
////////////////////////////////////////////// Local Water Zones /////////////////////////////////////////////////////////////
|
||
#if defined(KWS_USE_LOCAL_WATER_ZONES)
|
||
|
||
#define MAX_VISIBLE_LOCAL_ZONES 8
|
||
|
||
struct LocalZoneData
|
||
{
|
||
float3 center;
|
||
float3 halfSize;
|
||
float2x2 rotationMatrix; // (c0.x, c0.y, c1.x, c1.y)
|
||
uint id;
|
||
float2 uv;
|
||
|
||
float overrideColorSettings;
|
||
float transparent;
|
||
float4 waterColor;
|
||
float4 turbidityColor;
|
||
float useSphereBlending;
|
||
|
||
float overrideWindSettings;
|
||
float windStrengthMultiplier;
|
||
float windEdgeBlending;
|
||
|
||
float overrideHeight;
|
||
float heightEdgeBlending;
|
||
float clipWaterBelowZone;
|
||
};
|
||
|
||
|
||
StructuredBuffer<int> KWS_GlobalTileIndices_LocalZone;
|
||
StructuredBuffer<uint2> KWS_TileIndexRanges_LocalZone;
|
||
StructuredBuffer<LocalZoneData> KWS_ZoneData_LocalZone;
|
||
|
||
|
||
float2 _GridSize_LocalZone;
|
||
float3 _WorldMin_LocalZone;
|
||
float3 _WorldSize_LocalZone;
|
||
uint KWS_WaterLocalZonesCount;
|
||
|
||
bool GetTileRange_LocalZone(float3 worldPos, out uint offset, out uint count)
|
||
{
|
||
offset = 0;
|
||
count = 0;
|
||
|
||
float3 localPos = worldPos - _WorldMin_LocalZone.xyz;
|
||
float2 uvGrid = float2(localPos.x / _WorldSize_LocalZone.x, localPos.z / _WorldSize_LocalZone.z);
|
||
|
||
int x = floor(uvGrid.x * _GridSize_LocalZone.x);
|
||
int y = floor(uvGrid.y * _GridSize_LocalZone.y);
|
||
|
||
if (x < 0 || x >= _GridSize_LocalZone.x || y < 0 || y >= _GridSize_LocalZone.y)
|
||
{
|
||
return false;
|
||
}
|
||
else //metal require it
|
||
{
|
||
uint tileIndex = y * _GridSize_LocalZone.x + x;
|
||
|
||
uint2 range = KWS_TileIndexRanges_LocalZone[tileIndex];
|
||
offset = range.x;
|
||
uint size = range.y;
|
||
count = offset +size;
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
bool GetWaterZone_LocalZone(float3 worldPos, uint idx, out LocalZoneData zone)
|
||
{
|
||
zone = (LocalZoneData)0;
|
||
|
||
uint zoneID = KWS_GlobalTileIndices_LocalZone[idx];
|
||
if (zoneID == -1) return false;
|
||
else
|
||
{
|
||
zone = KWS_ZoneData_LocalZone[zoneID];
|
||
|
||
float2 pos = worldPos.xz - zone.center.xz;
|
||
float2 localPos = mul(pos, zone.rotationMatrix);
|
||
|
||
if (abs(localPos.x) > zone.halfSize.x || abs(localPos.y) > zone.halfSize.z)
|
||
{
|
||
return false;
|
||
}
|
||
else
|
||
{
|
||
zone.uv = localPos / zone.halfSize.xz * 0.5 + 0.5;
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
|
||
float GetLocalWaterZoneBlendFactor(float2 uv, float blendFactor)
|
||
{
|
||
uv = abs(uv * 2 - 1);
|
||
float uvEdgeMask = max(uv.x, uv.y);
|
||
uvEdgeMask = 1 - saturate(pow(uvEdgeMask * 1.01, blendFactor * 10));
|
||
return uvEdgeMask;
|
||
}
|
||
|
||
float GetLocalWaterZoneSphereBlendFactor(float2 uv, float blendFactor)
|
||
{
|
||
float2 localUV = uv * 2 - 1;
|
||
float dist = length(localUV);
|
||
float mask = 1 - saturate(pow(dist * 1.01, blendFactor * 4));
|
||
return mask;
|
||
}
|
||
|
||
float GetLocalWaterZoneWindBlendFactor(float2 uv, float blendFactor)
|
||
{
|
||
uv = abs(uv * 2 - 1);
|
||
float uvEdgeMask = max(uv.x, uv.y);
|
||
float fade = saturate(pow(uvEdgeMask * 1.01, blendFactor * 10));
|
||
return lerp(1, fade, blendFactor);
|
||
}
|
||
|
||
void EvaluateBlendedZoneData(inout LocalZoneData blendedZone, float3 rayStart, float3 rayDir, float rayLengthToSurface, float surfaceHeight, float noise)
|
||
{
|
||
UNITY_LOOP
|
||
for (uint zoneIdx = 0; zoneIdx < KWS_WaterLocalZonesCount; zoneIdx++)
|
||
{
|
||
LocalZoneData zone = KWS_ZoneData_LocalZone[zoneIdx];
|
||
float3 surfaceOffset = float3(0, max(0, zone.center.y + zone.halfSize.y - surfaceHeight) * 0.5f, 0);
|
||
|
||
float tEntry = 0;
|
||
|
||
float2 distanceToBox = abs(mul((rayStart.xz - zone.center.xz), zone.rotationMatrix)) / zone.halfSize.xz;
|
||
float distanceToBorder = max(distanceToBox.x, distanceToBox.y);
|
||
float zoneMinHeight = zone.center.y - zone.halfSize.y;
|
||
|
||
if (zone.overrideHeight > 0.5 && zone.clipWaterBelowZone && distanceToBorder < 1.1 && rayStart.y < zoneMinHeight && rayStart.y > KWS_WaterLevel)
|
||
{
|
||
blendedZone.transparent = 0;
|
||
return;
|
||
}
|
||
|
||
if (zone.overrideColorSettings > 0.5)
|
||
{
|
||
float density = 0;
|
||
if (zone.useSphereBlending > 0.5)
|
||
{
|
||
density = KWS_SDF_SphereDensity(rayStart, rayDir, zone.center, zone.halfSize.x, rayLengthToSurface, tEntry);
|
||
}
|
||
else
|
||
{
|
||
float2 boxSDF = KWS_SDF_IntersectionBox(rayStart , rayDir, zone.rotationMatrix, zone.center, zone.halfSize);
|
||
density = boxSDF.x < boxSDF.y && boxSDF.y > 0 && boxSDF.x < rayLengthToSurface;
|
||
tEntry = boxSDF.x;
|
||
}
|
||
|
||
|
||
if (density > 0)
|
||
{
|
||
density = saturate(density * 2);
|
||
density = lerp(0, density, saturate(blendedZone.transparent / max(1, tEntry)));
|
||
|
||
blendedZone.transparent = lerp(blendedZone.transparent, zone.transparent, density);
|
||
blendedZone.turbidityColor = lerp(blendedZone.turbidityColor, zone.turbidityColor, density);
|
||
blendedZone.waterColor = lerp(blendedZone.waterColor, zone.waterColor, density);
|
||
}
|
||
}
|
||
|
||
|
||
}
|
||
}
|
||
|
||
void EvaluateBlendedZoneDataWithHeight(inout LocalZoneData blendedZone, float3 rayStart, float3 rayDir, float rayLengthToSurface, float surfaceHeight, out float maxHeightOffset, out float offsetBlending)
|
||
{
|
||
maxHeightOffset = -100000;
|
||
offsetBlending = 0;
|
||
|
||
UNITY_LOOP
|
||
for (uint zoneIdx = 0; zoneIdx < KWS_WaterLocalZonesCount; zoneIdx++)
|
||
{
|
||
LocalZoneData zone = KWS_ZoneData_LocalZone[zoneIdx];
|
||
float3 surfaceOffset = float3(0, max(0, zone.center.y + zone.halfSize.y - surfaceHeight) * 0.5f, 0);
|
||
|
||
float tEntry = 0;
|
||
|
||
float2 distanceToBox = abs(mul((rayStart.xz - zone.center.xz), zone.rotationMatrix)) / zone.halfSize.xz;
|
||
float distanceToBorder = max(distanceToBox.x, distanceToBox.y);
|
||
float zoneMinHeight = zone.center.y - zone.halfSize.y;
|
||
|
||
if (zone.overrideHeight > 0.5 && zone.clipWaterBelowZone && distanceToBorder < 1.1 && rayStart.y < zoneMinHeight && rayStart.y > KWS_WaterLevel)
|
||
{
|
||
blendedZone.transparent = 0;
|
||
return;
|
||
}
|
||
|
||
if (zone.overrideColorSettings > 0.5)
|
||
{
|
||
float density = 0;
|
||
if (zone.useSphereBlending > 0.5)
|
||
{
|
||
density = KWS_SDF_SphereDensity(rayStart, rayDir, zone.center, zone.halfSize.x, rayLengthToSurface, tEntry);
|
||
}
|
||
else
|
||
{
|
||
float2 boxSDF = KWS_SDF_IntersectionBox(rayStart , rayDir, zone.rotationMatrix, zone.center, zone.halfSize);
|
||
density = boxSDF.x < boxSDF.y && boxSDF.y > 0 && boxSDF.x < rayLengthToSurface;
|
||
tEntry = boxSDF.x;
|
||
}
|
||
|
||
|
||
if (density > 0)
|
||
{
|
||
density = saturate(density * 2);
|
||
density = lerp(0, density, saturate(blendedZone.transparent / max(1, tEntry)));
|
||
|
||
blendedZone.transparent = lerp(blendedZone.transparent, zone.transparent, density);
|
||
blendedZone.turbidityColor = lerp(blendedZone.turbidityColor, zone.turbidityColor, density);
|
||
blendedZone.waterColor = lerp(blendedZone.waterColor, zone.waterColor, density);
|
||
}
|
||
}
|
||
|
||
if (zone.overrideHeight > 0.5)
|
||
{
|
||
float currentHeightOffset = zone.center.y + zone.halfSize.y - KWS_WaterLevel;
|
||
float heightFade = GetLocalWaterZoneSphereBlendFactor(zone.uv, zone.heightEdgeBlending);
|
||
maxHeightOffset = max(maxHeightOffset, currentHeightOffset);
|
||
offsetBlending = lerp(heightFade, 1, KWS_Pow20(zone.heightEdgeBlending));
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
#endif
|
||
|
||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
////////////////////////////////////////////// Dynamic waves //////////////////////////////////////////////////////////
|
||
|
||
Texture2DArray KWS_DynamicWavesMap;
|
||
Texture2DArray KWS_DynamicWavesAdditionalMap;
|
||
Texture2DArray KWS_DynamicWavesNormalAndWetMap;
|
||
Texture2DArray KWS_DynamicWavesAdvectedUVMap;
|
||
Texture2DArray KWS_DynamicWavesColorMap;
|
||
|
||
float3 KWS_DynamicWavesMapPos;
|
||
float4 KWS_DynamicWavesMapLodSizes;
|
||
float4 KWS_DynamicWavesMapLodSizesInverted;
|
||
|
||
float4 KWS_DynamicWavesMap_TexelSize;
|
||
|
||
struct DynamicWavesAdditionalData
|
||
{
|
||
uint zoneID;
|
||
float shorelineMask;
|
||
float foamMask;
|
||
float zoneFade;
|
||
};
|
||
|
||
struct DynamicWavesWetData
|
||
{
|
||
float wetMask;
|
||
float wetMapDepth;
|
||
};
|
||
|
||
float3 GetDynamicWavesMapUV(float3 worldPos, float distanceToCamera)
|
||
{
|
||
float2 localPos = worldPos.xz - KWS_DynamicWavesMapPos.xz;
|
||
float4 halfLodLimits = KWS_DynamicWavesMapLodSizes * 0.5;
|
||
|
||
// Create a 0–1 mask for each LOD: 1 if distance >= threshold, 0 if below
|
||
// (multiplying by a large constant mimics binary step without using step())
|
||
float4 thresholds = saturate((distanceToCamera - halfLodLimits) * 1e6);
|
||
|
||
// Compute the LOD index by summing thresholds (each adds 1 if passed)
|
||
float lodIndex = thresholds.x + thresholds.y + thresholds.z;
|
||
|
||
// Select the correct inverse LOD size (scale) based on which threshold was last passed
|
||
// This works without conditionals or ternary operators
|
||
float4 invSizes = KWS_DynamicWavesMapLodSizesInverted;
|
||
float invSize = (1.0 - thresholds.x) * invSizes.x + (thresholds.x - thresholds.y) * invSizes.y + (thresholds.y - thresholds.z) * invSizes.z + thresholds.z * invSizes.w;
|
||
|
||
// Convert to UVs in the projection texture
|
||
float2 uv = localPos * invSize + 0.5;
|
||
|
||
// Return UV + selected LOD index (for use in SampleLevel)
|
||
return float3(uv, lodIndex);
|
||
}
|
||
|
||
|
||
float4 GetDynamicWavesMap(float3 uv)
|
||
{
|
||
return KWS_DynamicWavesMap.SampleLevel(sampler_linear_clamp, uv, 0);
|
||
}
|
||
|
||
float4 GetDynamicWavesMapBicubic(float3 uv)
|
||
{
|
||
return Texture2DArraySampleLevelBicubic(KWS_DynamicWavesMap, sampler_linear_clamp, uv.xy, KWS_DynamicWavesMap_TexelSize, uv.z, 0);
|
||
}
|
||
|
||
DynamicWavesAdditionalData GetDynamicWavesAdditionalMap(float3 uv)
|
||
{
|
||
float4 rawData = KWS_DynamicWavesAdditionalMap.SampleLevel(sampler_linear_clamp, uv, 0);
|
||
|
||
DynamicWavesAdditionalData data;
|
||
data.zoneID = Unpack_R8_UNorm_ToUint(rawData.x);
|
||
data.shorelineMask = rawData.y;
|
||
data.foamMask = rawData.z;
|
||
data.zoneFade= rawData.w;
|
||
|
||
return data;
|
||
}
|
||
|
||
DynamicWavesAdditionalData GetDynamicWavesAdditionalMapBicubic(float3 uv)
|
||
{
|
||
float4 rawData = Texture2DArraySampleLevelBicubic(KWS_DynamicWavesAdditionalMap, sampler_linear_clamp, uv.xy, KWS_DynamicWavesMap_TexelSize, uv.z, 0);
|
||
|
||
DynamicWavesAdditionalData data;
|
||
data.zoneID = Unpack_R8_UNorm_ToUint(rawData.x);
|
||
data.shorelineMask = rawData.y;
|
||
data.foamMask = rawData.z;
|
||
data.zoneFade= rawData.w;
|
||
|
||
return data;
|
||
}
|
||
|
||
float3 GetDynamicWavesNormalMap(float3 uv)
|
||
{
|
||
float2 data = KWS_DynamicWavesNormalAndWetMap.SampleLevel(sampler_linear_clamp, uv, 0).xy * 2 - 1;
|
||
return normalize(float3(data.x, 1, data.y));
|
||
}
|
||
|
||
float3 GetDynamicWavesNormalMapBicubic(float3 uv)
|
||
{
|
||
float2 data = Texture2DArraySampleLevelBicubic(KWS_DynamicWavesNormalAndWetMap, sampler_linear_clamp, uv.xy, KWS_DynamicWavesMap_TexelSize, uv.z, 0).xy * 2 - 1;
|
||
return normalize(float3(data.x, 1, data.y));
|
||
}
|
||
|
||
|
||
DynamicWavesWetData GetDynamicWavesWetMap(float3 uv)
|
||
{
|
||
float2 rawData = KWS_DynamicWavesNormalAndWetMap.SampleLevel(sampler_linear_clamp, uv, 0).zw;
|
||
|
||
DynamicWavesWetData data;
|
||
data.wetMask = rawData.x;
|
||
data.wetMapDepth = rawData.y;
|
||
return data;
|
||
}
|
||
|
||
DynamicWavesWetData GetDynamicWavesWetMapBicubic(float3 uv)
|
||
{
|
||
float2 rawData = Texture2DArraySampleLevelBicubic(KWS_DynamicWavesNormalAndWetMap, sampler_linear_clamp, uv.xy, KWS_DynamicWavesMap_TexelSize, uv.z, 0).zw;
|
||
|
||
DynamicWavesWetData data;
|
||
data.wetMask = rawData.x;
|
||
data.wetMapDepth = rawData.y;
|
||
return data;
|
||
}
|
||
|
||
|
||
float4 GetDynamicWavesAdvectedUVMap(float3 uv)
|
||
{
|
||
return KWS_DynamicWavesAdvectedUVMap.SampleLevel(sampler_linear_clamp, uv, 0).xyzw;
|
||
}
|
||
|
||
float4 GetDynamicWavesAdvectedUVMapBicubic(float3 uv)
|
||
{
|
||
return Texture2DArraySampleLevelBicubic(KWS_DynamicWavesAdvectedUVMap, sampler_linear_clamp, uv.xy, KWS_DynamicWavesMap_TexelSize, uv.z, 0).xyzw;
|
||
}
|
||
|
||
float4 GetDynamicWavesColorMap(float3 uv)
|
||
{
|
||
return KWS_DynamicWavesColorMap.SampleLevel(sampler_linear_clamp, uv, 0);
|
||
}
|
||
|
||
#define MAX_ZONES_PER_TILE 8
|
||
|
||
|
||
Texture2D KWS_DynamicWaves;
|
||
Texture2D KWS_DynamicWavesNormals;
|
||
Texture2D KWS_DynamicWavesLast;
|
||
Texture2D KWS_DynamicWavesAdditionalDataRT;
|
||
Texture2D KWS_DynamicWavesColorDataRT;
|
||
Texture2D KWS_DynamicWavesMaskRT;
|
||
Texture2D KWS_DynamicWavesMaskColorRT;
|
||
Texture2D KWS_DynamicWavesDepthMask;
|
||
Texture2D KWS_DynamicWavesAdvectedUV;
|
||
|
||
|
||
Texture2D KWS_DynamicWaves0;
|
||
Texture2D KWS_DynamicWaves1;
|
||
Texture2D KWS_DynamicWaves2;
|
||
Texture2D KWS_DynamicWaves3;
|
||
Texture2D KWS_DynamicWaves4;
|
||
Texture2D KWS_DynamicWaves5;
|
||
Texture2D KWS_DynamicWaves6;
|
||
Texture2D KWS_DynamicWaves7;
|
||
|
||
Texture2D KWS_DynamicWavesNormals0;
|
||
Texture2D KWS_DynamicWavesNormals1;
|
||
Texture2D KWS_DynamicWavesNormals2;
|
||
Texture2D KWS_DynamicWavesNormals3;
|
||
Texture2D KWS_DynamicWavesNormals4;
|
||
Texture2D KWS_DynamicWavesNormals5;
|
||
Texture2D KWS_DynamicWavesNormals6;
|
||
Texture2D KWS_DynamicWavesNormals7;
|
||
|
||
Texture2D KWS_DynamicWavesAdditionalDataRT0;
|
||
Texture2D KWS_DynamicWavesAdditionalDataRT1;
|
||
Texture2D KWS_DynamicWavesAdditionalDataRT2;
|
||
Texture2D KWS_DynamicWavesAdditionalDataRT3;
|
||
Texture2D KWS_DynamicWavesAdditionalDataRT4;
|
||
Texture2D KWS_DynamicWavesAdditionalDataRT5;
|
||
Texture2D KWS_DynamicWavesAdditionalDataRT6;
|
||
Texture2D KWS_DynamicWavesAdditionalDataRT7;
|
||
|
||
Texture2D KWS_DynamicWavesColorDataRT0;
|
||
Texture2D KWS_DynamicWavesColorDataRT1;
|
||
Texture2D KWS_DynamicWavesColorDataRT2;
|
||
Texture2D KWS_DynamicWavesColorDataRT3;
|
||
Texture2D KWS_DynamicWavesColorDataRT4;
|
||
Texture2D KWS_DynamicWavesColorDataRT5;
|
||
Texture2D KWS_DynamicWavesColorDataRT6;
|
||
Texture2D KWS_DynamicWavesColorDataRT7;
|
||
|
||
Texture2D KWS_DynamicWavesDepthMask0;
|
||
Texture2D KWS_DynamicWavesDepthMask1;
|
||
Texture2D KWS_DynamicWavesDepthMask2;
|
||
Texture2D KWS_DynamicWavesDepthMask3;
|
||
Texture2D KWS_DynamicWavesDepthMask4;
|
||
Texture2D KWS_DynamicWavesDepthMask5;
|
||
Texture2D KWS_DynamicWavesDepthMask6;
|
||
Texture2D KWS_DynamicWavesDepthMask7;
|
||
|
||
Texture2D KWS_DynamicWavesAdvectedUV0;
|
||
Texture2D KWS_DynamicWavesAdvectedUV1;
|
||
Texture2D KWS_DynamicWavesAdvectedUV2;
|
||
Texture2D KWS_DynamicWavesAdvectedUV3;
|
||
Texture2D KWS_DynamicWavesAdvectedUV4;
|
||
Texture2D KWS_DynamicWavesAdvectedUV5;
|
||
Texture2D KWS_DynamicWavesAdvectedUV6;
|
||
Texture2D KWS_DynamicWavesAdvectedUV7;
|
||
Texture2D KWS_DynamicWavesAdvectedUV8;
|
||
|
||
float4 KWS_DynamicWaves0_TexelSize;
|
||
float4 KWS_DynamicWaves1_TexelSize;
|
||
float4 KWS_DynamicWaves2_TexelSize;
|
||
float4 KWS_DynamicWaves3_TexelSize;
|
||
float4 KWS_DynamicWaves4_TexelSize;
|
||
float4 KWS_DynamicWaves5_TexelSize;
|
||
float4 KWS_DynamicWaves6_TexelSize;
|
||
float4 KWS_DynamicWaves7_TexelSize;
|
||
|
||
float4 KWS_DynamicWaves_TexelSize;
|
||
float4 KWS_DynamicWavesDepthMask_TexelSize;
|
||
float4 KWS_DynamicWavesAdditionalDataRT_TexelSize;
|
||
|
||
uint KWS_DynamicWavesZoneID;
|
||
float3 KWS_DynamicWavesZonePosition;
|
||
float3 KWS_DynamicWavesZoneSize;
|
||
float4 KWS_DynamicWavesZoneRotationMatrix;
|
||
float KWS_DynamicWavesZoneFlowSpeedMultiplier;
|
||
float4 KWS_DynamicWavesZoneFoamData;
|
||
|
||
|
||
uint KWS_DynamicWavesUseFoamTexture;
|
||
uint KWS_DynamicWavesUseAdvectedUV;
|
||
|
||
float3 KWS_DynamicWavesZonePositionArray[MAX_ZONES_PER_TILE];
|
||
float3 KWS_DynamicWavesZoneSizeArray[MAX_ZONES_PER_TILE];
|
||
float4 KWS_DynamicWavesOrthoDepthNearFarSizeArray[MAX_ZONES_PER_TILE];
|
||
float4 KWS_DynamicWavesZoneRotationMatrixArray[MAX_ZONES_PER_TILE];
|
||
|
||
float KWS_DynamicWavesBakingMode;
|
||
float KWS_BakedZoneInPreviewMode;
|
||
|
||
#define DYNAMIC_WAVE_COLOR_MAX_TRANSPARENT 4
|
||
#define DYNAMIC_WAVE_PROCEDURAL_MASK_TYPE_SPHERE 1
|
||
|
||
#define KWS_DYNAMIC_WAVE_PARTICLE_TYPE_FOAM 0
|
||
#define KWS_DYNAMIC_WAVE_PARTICLE_TYPE_SPLASH 1
|
||
#define KWS_DYNAMIC_WAVE_PARTICLE_TYPE_SPLASH_SURFACE 2
|
||
|
||
|
||
struct KWS_DynamicWavesMask
|
||
{
|
||
uint zoneInteractionType;
|
||
float force;
|
||
float waterHeight;
|
||
uint useColor;
|
||
|
||
float4 size;
|
||
float4 position;
|
||
|
||
float3 forceDirection;
|
||
uint useWaterIntersection;
|
||
|
||
float4 color;
|
||
float4x4 matrixTRS;
|
||
};
|
||
|
||
struct FoamParticle
|
||
{
|
||
float3 position;
|
||
float initialRandom01;
|
||
|
||
float3 prevPosition;
|
||
float prevLifetime;
|
||
|
||
float3 velocity;
|
||
float currentLifetime;
|
||
|
||
float isFreeMoving;
|
||
float shorelineMask;
|
||
float maxLifeTime;
|
||
float _pad;
|
||
};
|
||
|
||
struct SplashParticle
|
||
{
|
||
float initialRandom01;
|
||
float3 position;
|
||
|
||
float3 velocity;
|
||
float currentLifetime;
|
||
|
||
float shorelineMask;
|
||
float distanceToSurface;
|
||
float uvOffset;
|
||
float initialSpeed;
|
||
|
||
float3 prevPosition;
|
||
float prevLifetime;
|
||
};
|
||
|
||
|
||
struct ZoneData
|
||
{
|
||
float3 center;
|
||
float3 halfSize;
|
||
float2x2 rotationMatrix; // (c0.x, c0.y, c1.x, c1.y)
|
||
uint id;
|
||
float2 uv;
|
||
float flowSpeedMultiplier;
|
||
uint useAdvectedUV;
|
||
uint useFoamTexture;
|
||
float4 foamData;
|
||
};
|
||
|
||
#if defined(KWS_USE_DYNAMIC_WAVES) || defined(KWS_USE_COLORED_DYNAMIC_WAVES)
|
||
|
||
StructuredBuffer<KWS_DynamicWavesMask> KWS_DynamicWavesMaskBuffer;
|
||
StructuredBuffer<SplashParticle> KWS_SplashParticlesBuffer;
|
||
StructuredBuffer<FoamParticle> KWS_FoamParticlesBuffer;
|
||
StructuredBuffer<ZoneData> KWS_ZoneData;
|
||
|
||
#endif
|
||
|
||
float2 _GridSize;
|
||
float3 _WorldMin;
|
||
float3 _WorldSize;
|
||
uint KWS_WaterDynamicWavesZonesCount;
|
||
|
||
float3 KWS_ZonePosition;
|
||
float3 KWS_ZoneSize;
|
||
float4 KWS_ZoneRotation;
|
||
|
||
|
||
inline float2 RotateDynamicWavesCoord(float2 coord)
|
||
{
|
||
return float2(dot(coord, KWS_DynamicWavesZoneRotationMatrix.xy), dot(coord, KWS_DynamicWavesZoneRotationMatrix.zw));
|
||
}
|
||
|
||
inline float2 RotateDynamicWavesCoord(uint id, float2 coord)
|
||
{
|
||
float4 mat = KWS_DynamicWavesZoneRotationMatrixArray[id];
|
||
float2x2 invRot = float2x2(mat.x, mat.z, mat.y, mat.w);
|
||
float2 rotated = mul(coord, invRot);
|
||
|
||
return rotated;
|
||
}
|
||
|
||
|
||
inline float2 RotateDynamicWavesCoordInverse(float2 coord)
|
||
{
|
||
return float2(dot(coord, KWS_DynamicWavesZoneRotationMatrix.xz), dot(coord, KWS_DynamicWavesZoneRotationMatrix.yw));
|
||
}
|
||
|
||
inline float2 GetDynamicWavesUV(float3 worldPos)
|
||
{
|
||
return (worldPos.xz - KWS_DynamicWavesZonePosition.xz) / KWS_DynamicWavesZoneSize.xz + 0.5;
|
||
}
|
||
|
||
inline float2 GetDynamicWavesUVRotated(float3 worldPos)
|
||
{
|
||
float2 local = worldPos.xz - KWS_DynamicWavesZonePosition.xz;
|
||
|
||
float2x2 invRot = float2x2(
|
||
KWS_DynamicWavesZoneRotationMatrix.x, KWS_DynamicWavesZoneRotationMatrix.z,
|
||
KWS_DynamicWavesZoneRotationMatrix.y, KWS_DynamicWavesZoneRotationMatrix.w
|
||
);
|
||
|
||
float2 rotated = mul(invRot, local);
|
||
return rotated / KWS_DynamicWavesZoneSize.xz + 0.5;
|
||
}
|
||
|
||
|
||
float EncodeDynamicWavesHeight(float worldHeight)
|
||
{
|
||
float minY = KWS_DynamicWavesZonePosition.y - KWS_DynamicWavesZoneSize.y;
|
||
float maxY = KWS_DynamicWavesZonePosition.y + KWS_DynamicWavesZoneSize.y;
|
||
return saturate((worldHeight - minY) / (maxY - minY));
|
||
}
|
||
|
||
float DecodeDynamicWavesHeight( float worldHeight, float3 zonePos, float3 zoneSize)
|
||
{
|
||
|
||
return lerp(zonePos.y - zoneSize.y, zonePos.y + zoneSize.y, worldHeight);
|
||
}
|
||
|
||
float DecodeDynamicWavesHeight(float worldHeight)
|
||
{
|
||
float zoneCenter = KWS_DynamicWavesZonePosition.y;
|
||
float zoneSize = KWS_DynamicWavesZoneSize.y;
|
||
|
||
return lerp(zoneCenter - zoneSize, zoneCenter + zoneSize, worldHeight);
|
||
}
|
||
|
||
inline float4 GetDynamicWavesMask(float2 uv)
|
||
{
|
||
float threshold = 4.0 / 255.0;
|
||
float4 data = KWS_DynamicWavesMaskRT.SampleLevel(sampler_linear_clamp, uv, 0);
|
||
data.xyz = data.xyz * 2 - 1;
|
||
data.xyz *= step(threshold, abs(data.xyz));
|
||
return data;
|
||
}
|
||
|
||
|
||
float GetWaterToZoneHeight()
|
||
{
|
||
return abs(KWS_DynamicWavesZonePosition.y + KWS_DynamicWavesZoneSize.y * 0.5 - KWS_WaterLevel);
|
||
}
|
||
|
||
float PackWaterZoneDepth(float w)
|
||
{
|
||
float yMin = KWS_DynamicWavesZonePosition.y - KWS_DynamicWavesZoneSize.y * 0.5;
|
||
float yMax = KWS_DynamicWavesZonePosition.y + KWS_DynamicWavesZoneSize.y * 0.5;
|
||
return saturate((w - yMin) / (yMax - yMin));
|
||
}
|
||
|
||
float UnpackWaterZoneDepth(float w)
|
||
{
|
||
float yMin = KWS_DynamicWavesZonePosition.y - KWS_DynamicWavesZoneSize.y * 0.5;
|
||
float yMax = KWS_DynamicWavesZonePosition.y + KWS_DynamicWavesZoneSize.y * 0.5;
|
||
return w *(yMax-yMin) + yMin;
|
||
}
|
||
|
||
float4 PackSimulation(float4 value)
|
||
{
|
||
value.xy = clamp(value.xy, -10, 10) / 20.0 + 0.5;
|
||
value.z = (clamp(value.z, -2, 20) + 2) / 22.0;
|
||
value.w = value.w / GetWaterToZoneHeight();
|
||
return value;
|
||
}
|
||
|
||
|
||
float4 UnpackSimulation(float4 value)
|
||
{
|
||
value.xy = (value.xy - 0.5) * 20.0;
|
||
value.z = value.z * 22.0 - 2.0;
|
||
value.w = value.w * GetWaterToZoneHeight();
|
||
return value;
|
||
}
|
||
|
||
|
||
|
||
inline float4 GetDynamicWavesMaskColor(float2 uv)
|
||
{
|
||
return KWS_DynamicWavesMaskColorRT.SampleLevel(sampler_linear_clamp, uv, 0);
|
||
}
|
||
|
||
inline float4 GetDynamicWavesZoneRaw(float2 uv)
|
||
{
|
||
return KWS_DynamicWaves.SampleLevel(sampler_linear_clamp, uv, 0);
|
||
}
|
||
|
||
inline float4 GetDynamicWavesZone(float2 uv)
|
||
{
|
||
float4 data = UnpackSimulation(KWS_DynamicWaves.SampleLevel(sampler_linear_clamp, uv, 0));
|
||
data.xy = RotateDynamicWavesCoord(data.xy);
|
||
return data;
|
||
}
|
||
|
||
inline float4 GetDynamicWavesZone(float2 uv, float2 offset)
|
||
{
|
||
float4 data = UnpackSimulation(KWS_DynamicWaves.SampleLevel(sampler_linear_clamp, uv + offset * KWS_DynamicWaves_TexelSize.xy, 0));
|
||
data.xy = RotateDynamicWavesCoord(data.xy);
|
||
return data;
|
||
}
|
||
|
||
|
||
inline float4 GetDynamicWavesZoneBicubic(float2 uv)
|
||
{
|
||
float4 data = UnpackSimulation(Texture2DSampleLevelBicubic(KWS_DynamicWaves, sampler_linear_clamp, uv, KWS_DynamicWaves_TexelSize, 0));
|
||
data.xy = RotateDynamicWavesCoord(data.xy);
|
||
return data;
|
||
}
|
||
|
||
|
||
inline float4 GetDynamicWavesZoneAdditionalData(float2 uv)
|
||
{
|
||
return KWS_DynamicWavesAdditionalDataRT.SampleLevel(sampler_linear_clamp, uv, 0);
|
||
}
|
||
|
||
|
||
inline float4 GetDynamicWavesZoneAdditionalDataBicubic(float2 uv)
|
||
{
|
||
return Texture2DSampleLevelBicubic(KWS_DynamicWavesAdditionalDataRT, sampler_linear_clamp, uv, KWS_DynamicWavesAdditionalDataRT_TexelSize, 0);
|
||
}
|
||
|
||
inline float4 GetDynamicWavesZoneColorData(float2 uv)
|
||
{
|
||
return KWS_DynamicWavesColorDataRT.SampleLevel(sampler_linear_clamp, uv, 0);
|
||
}
|
||
|
||
|
||
inline float4 GetDynamicWavesZoneAdvectedUV(float2 uv)
|
||
{
|
||
return KWS_DynamicWavesAdvectedUV.SampleLevel(sampler_linear_clamp, uv, 0);
|
||
}
|
||
|
||
|
||
inline float3 GetDynamicWavesZoneNormals(float2 uv)
|
||
{
|
||
return KWS_DynamicWavesNormals.SampleLevel(sampler_linear_clamp, uv, 0).xyz;
|
||
}
|
||
|
||
|
||
inline float3 GetDynamicWavesZoneNormalsBicubic(float2 uv)
|
||
{
|
||
return Texture2DSampleLevelBicubic(KWS_DynamicWavesNormals, sampler_linear_clamp, uv, KWS_DynamicWaves_TexelSize, 0).xyz;
|
||
}
|
||
|
||
inline float UnpackDepthMask(float maskDepth)
|
||
{
|
||
if (maskDepth > 0)
|
||
{
|
||
float cameraHeight = KWS_OrthoDepthNearFarSize.x;
|
||
float far = KWS_OrthoDepthNearFarSize.y;
|
||
float near = 0.0001;
|
||
|
||
float worldDepth = cameraHeight - far + near + maskDepth * far;
|
||
return worldDepth;
|
||
}
|
||
else return -100000;
|
||
}
|
||
|
||
|
||
|
||
inline float GetDynamicWavesZoneDepthMaskBicubic(float2 uv)
|
||
{
|
||
//return 0;
|
||
float maskDepth = Texture2DSampleLevelBicubic(KWS_DynamicWavesDepthMask, sampler_linear_clamp, uv, KWS_DynamicWavesDepthMask_TexelSize, 0).x;
|
||
return UnpackDepthMask(maskDepth);
|
||
}
|
||
|
||
inline float GetDynamicWavesZoneDepthMask(float2 uv)
|
||
{
|
||
//return 0;
|
||
float maskDepth = KWS_DynamicWavesDepthMask.SampleLevel(sampler_linear_clamp, uv, 0).x;
|
||
return UnpackDepthMask(maskDepth);
|
||
}
|
||
|
||
|
||
|
||
inline float GetDynamicWavesBorderFading(float2 uv, float multiplier = 1.01, float powValue = 15)
|
||
{
|
||
uv = abs(uv * 2 - 1);
|
||
float uvEdgeMask = max(uv.x, uv.y);
|
||
uvEdgeMask = 1 - saturate(pow(uvEdgeMask * multiplier, powValue));
|
||
return uvEdgeMask;
|
||
}
|
||
|
||
inline float2 NormalizeDynamicWavesVelocity(float2 velocity)
|
||
{
|
||
float flowStrength = max(length(velocity), 0.001);
|
||
return (velocity / flowStrength) * saturate(1 - exp(-flowStrength));
|
||
}
|
||
|
||
|
||
float GetDynamicWavesHeightOffset(float3 worldPos, uint iterations = 3)
|
||
{
|
||
float3 disp = GetFftWavesHeight(worldPos, iterations);
|
||
|
||
float2 uv = GetDynamicWavesUV(worldPos);
|
||
float4 dynamicWaves = GetDynamicWavesZone(uv);
|
||
float zoneFade = GetDynamicWavesBorderFading(uv);
|
||
|
||
float waterLevel = disp.y + dynamicWaves.z * zoneFade + dynamicWaves.w + KWS_WaterLevel;
|
||
return waterLevel;
|
||
}
|
||
|
||
float GetDynamicWavesHeightOffset(float3 worldPos, float2 dynamicWavesUV, float4 dynamicWaves, uint iterations = 3)
|
||
{
|
||
float3 disp = 0;
|
||
if (KWS_WindSpeed > 6)
|
||
{
|
||
disp = GetFftWavesHeight(worldPos, iterations);
|
||
}
|
||
|
||
float zoneFade = GetDynamicWavesBorderFading(dynamicWavesUV);
|
||
|
||
float waterLevel = disp.y + dynamicWaves.z * zoneFade + dynamicWaves.w + KWS_WaterLevel;
|
||
return waterLevel;
|
||
}
|
||
|
||
float GetDynamicWavesWaterfallTreshold(float3 zoneNormal)
|
||
{
|
||
float waterfallThreshold = saturate(2 * saturate(1 - dot(zoneNormal, float3(0, 1, 0))) - 0.05);
|
||
return waterfallThreshold;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
|
||
|
||
////////////////////////////////////////////// Underwater //////////////////////////////////////////////////////////
|
||
#define UNDERWATER_DEPTH_SCALE 0.75
|
||
|
||
|
||
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
|
||
|
||
////////////////////////////////////////////// Refraction //////////////////////////////////////////////////////////
|
||
|
||
inline void FixRefractionSurfaceLeaking(float surfaceDepthZEye, float sceneZ, float sceneZEye, float2 screenUV, inout float refractedSceneZ, inout float refractedSceneZEye, inout float2 refractionUV)
|
||
{
|
||
if (surfaceDepthZEye > refractedSceneZEye)
|
||
{
|
||
refractedSceneZ = sceneZ;
|
||
refractedSceneZEye = sceneZEye;
|
||
refractionUV = screenUV;
|
||
}
|
||
}
|
||
|
||
half3 ComputeWaterRefractRay(half3 viewDir, half3 normal, half depth)
|
||
{
|
||
half nv = dot(normal, viewDir);
|
||
half v2 = dot(viewDir, viewDir);
|
||
half knormal = (sqrt(((1.7689 - 1.0) * v2) / (nv * nv) + 1.0) - 1.0) * nv;
|
||
half3 result = depth * (viewDir + (knormal * normal));
|
||
return result;
|
||
}
|
||
|
||
|
||
|
||
inline float2 GetRefractedUV_IOR(float3 viewDir, half3 normal, float3 worldPos, float sceneZEye, float waterSurfaceZEye, float transparent, float depthValue)
|
||
{
|
||
float zFix = saturate(sceneZEye - waterSurfaceZEye);
|
||
float aproximatedDepth = min(transparent, depthValue * zFix);
|
||
float3 refractedRay = ComputeWaterRefractRay(-viewDir, normal, aproximatedDepth);
|
||
refractedRay.y *= 0.4; //fix information lost in the near camera
|
||
|
||
float4 refractedClipPos = mul(UNITY_MATRIX_VP, float4(GetCameraRelativePosition(worldPos + refractedRay), 1.0));
|
||
float4 refractionScreenPos = ComputeScreenPos(refractedClipPos);
|
||
float2 uv = refractionScreenPos.xy / refractionScreenPos.w;
|
||
|
||
/*float2 overflowUV = abs(uv * 2 - 1);
|
||
float overflowFix = saturate(max(overflowUV.x, overflowUV.y) - 0.6);
|
||
overflowFix *= overflowFix;
|
||
overflowFix = lerp(0, overflowFix, zFix);
|
||
uv = lerp(uv, uv * 0.5 + 0.25, overflowFix);*/
|
||
|
||
if (uv.x >= 0.995) uv.x = 1.99 - uv.x;
|
||
if (uv.y >= 0.995) uv.y = 1.99 - uv.y;
|
||
if (uv.y <= 0) uv.y = -uv.y;
|
||
if (uv.x <= 0) uv.x = -uv.x;
|
||
|
||
return uv;
|
||
}
|
||
|
||
inline float2 GetRefractedUV_Simple(float2 uv, half3 normal)
|
||
{
|
||
return uv + normal.xz * KWS_RefractionSimpleStrength * 0.5;
|
||
}
|
||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
|
||
|
||
|
||
float4 LocalPosToToClipPosOrtho(float3 vertex)
|
||
{
|
||
float3 worldPos = GetCameraRelativePositionOrtho(mul(UNITY_MATRIX_M, float4(vertex.xyz, 1.0)).xyz);
|
||
return mul(KWS_MATRIX_VP_ORTHO, float4(GetCameraAbsolutePosition(worldPos), 1));
|
||
}
|
||
|
||
float4 WorldPosToToClipPosOrtho(float3 worldPos)
|
||
{
|
||
worldPos = GetCameraRelativePositionOrtho(worldPos);
|
||
return mul(KWS_MATRIX_VP_ORTHO, float4(worldPos, 1));
|
||
}
|
||
|
||
|
||
inline half GetSurfaceToSceneFading(float zEye, float surfaceZEye, float multiplier)
|
||
{
|
||
return saturate((zEye - surfaceZEye) * multiplier);
|
||
}
|
||
|
||
inline half GetWaterRawFade(float3 worldPos, float surfaceDepthZEye, float refractedSceneZEye, half surfaceMask, half depthAngleFix)
|
||
{
|
||
return (refractedSceneZEye - surfaceDepthZEye) * lerp(depthAngleFix, 1, unity_OrthoParams.w);
|
||
}
|
||
|
||
|
||
|
||
|
||
////////////////////////////////////////////// Scene Color Pass //////////////////////////////////////////////////////////
|
||
|
||
float4 KWS_CameraOpaqueTextureAfterWaterPass_TexelSize;
|
||
float4 KWS_CameraOpaqueTextureAfterWaterPass_RTHandleScale;
|
||
|
||
DECLARE_TEXTURE(KWS_CameraOpaqueTextureAfterWaterPass);
|
||
|
||
|
||
inline float2 GetSceneColorAfterWaterPassNormalizedUV(float2 uv)
|
||
{
|
||
float2 maxCoord = 1.0f - KWS_CameraOpaqueTextureAfterWaterPass_TexelSize.xy * 0.5;
|
||
return min(uv, maxCoord) * KWS_CameraOpaqueTextureAfterWaterPass_RTHandleScale.xy;
|
||
}
|
||
|
||
inline half3 GetSceneColorAfterWaterPass(float2 uv)
|
||
{
|
||
#ifdef KWS_HDRP
|
||
return GetSceneColor(uv);
|
||
#else
|
||
return SAMPLE_TEXTURE_LOD(KWS_CameraOpaqueTextureAfterWaterPass, sampler_linear_clamp, GetSceneColorAfterWaterPassNormalizedUV(uv), 0).xyz;
|
||
#endif
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
#endif |