修改水
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
#ifndef CREST_WATER_ALPHA_H
|
||||
#define CREST_WATER_ALPHA_H
|
||||
|
||||
#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/InputsDriven.hlsl"
|
||||
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Helpers.hlsl"
|
||||
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Cascade.hlsl"
|
||||
|
||||
m_CrestNameSpace
|
||||
|
||||
float ClipSurface(const float2 i_PositionWSXZ)
|
||||
{
|
||||
// Do not include transition slice to avoid blending as we do a black border instead.
|
||||
uint slice0; uint slice1; float alpha;
|
||||
PosToSliceIndices(i_PositionWSXZ, 0.0, g_Crest_LodCount - 1.0, g_Crest_WaterScale, slice0, slice1, alpha);
|
||||
|
||||
const Cascade cascade0 = Cascade::Make(slice0);
|
||||
const Cascade cascade1 = Cascade::Make(slice1);
|
||||
const float weight0 = (1.0 - alpha) * cascade0._Weight;
|
||||
const float weight1 = (1.0 - weight0) * cascade1._Weight;
|
||||
|
||||
float value = 0.0;
|
||||
|
||||
if (weight0 > m_CrestSampleLodThreshold)
|
||||
{
|
||||
Cascade::MakeClip(slice0).SampleClip(i_PositionWSXZ, weight0, value);
|
||||
}
|
||||
if (weight1 > m_CrestSampleLodThreshold)
|
||||
{
|
||||
Cascade::MakeClip(slice1).SampleClip(i_PositionWSXZ, weight1, value);
|
||||
}
|
||||
|
||||
return lerp(g_Crest_ClipByDefault, value, weight0 + weight1);
|
||||
}
|
||||
|
||||
m_CrestNameSpaceEnd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c1e69a8c6920249c1ad0b50907793046
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,181 @@
|
||||
// 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
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b2ee0978718e447e3ab93a881f3d5dcf
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,224 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
#ifndef CREST_WATER_FOAM_H
|
||||
#define CREST_WATER_FOAM_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
|
||||
|
||||
half WhiteFoamTexture
|
||||
(
|
||||
const TiledTexture i_Texture,
|
||||
const half i_Foam,
|
||||
const half i_Feather,
|
||||
const float2 i_WorldXZ0,
|
||||
const float2 i_WorldXZ1,
|
||||
const float2 i_TexelOffset,
|
||||
const half i_LodAlpha,
|
||||
const Cascade i_CascadeData0
|
||||
)
|
||||
{
|
||||
const float2 uvOffset = i_TexelOffset + g_Crest_Time * i_Texture._speed / 32.0;
|
||||
// Scale with lods to get multiscale detail. 10 is magic number that gets the
|
||||
// material 'scale' slider into an intuitive range.
|
||||
const float scale = i_Texture._scale * i_CascadeData0._Scale / 10.0;
|
||||
|
||||
half ft = lerp
|
||||
(
|
||||
i_Texture.Sample((i_WorldXZ0 + uvOffset) / scale).r,
|
||||
i_Texture.Sample((i_WorldXZ1 + uvOffset) / (2.0 * scale)).r,
|
||||
i_LodAlpha
|
||||
);
|
||||
|
||||
// Black point fade.
|
||||
half result = saturate(1.0 - i_Foam);
|
||||
return smoothstep(result, result + i_Feather, ft);
|
||||
}
|
||||
|
||||
half MultiScaleFoamAlbedo
|
||||
(
|
||||
const TiledTexture i_Texture,
|
||||
const half i_Feather,
|
||||
const half i_FoamData,
|
||||
const Cascade i_CascadeData0,
|
||||
const Cascade i_CascadeData1,
|
||||
const half i_LodAlpha,
|
||||
const float2 i_UndisplacedXZ
|
||||
)
|
||||
{
|
||||
float2 worldXZ0 = i_UndisplacedXZ;
|
||||
float2 worldXZ1 = i_UndisplacedXZ;
|
||||
|
||||
#if (CREST_SHIFTING_ORIGIN != 0)
|
||||
// Apply tiled floating origin offset. Only needed if:
|
||||
// - _FoamScale is a non integer value
|
||||
// - _FoamScale is over 48
|
||||
worldXZ0 -= ShiftingOriginOffset(i_Texture, i_CascadeData0);
|
||||
worldXZ1 -= ShiftingOriginOffset(i_Texture, i_CascadeData1);
|
||||
#endif // CREST_SHIFTING_ORIGIN
|
||||
|
||||
return WhiteFoamTexture(i_Texture, i_FoamData, i_Feather, worldXZ0, worldXZ1, (float2)0.0, i_LodAlpha, i_CascadeData0);
|
||||
}
|
||||
|
||||
half2 MultiScaleFoamNormal
|
||||
(
|
||||
const TiledTexture i_Texture,
|
||||
const half i_Feather,
|
||||
const half i_NormalStrength,
|
||||
const half i_FoamData,
|
||||
const half i_FoamAlbedo,
|
||||
const Cascade i_CascadeData0,
|
||||
const Cascade i_CascadeData1,
|
||||
const half i_LodAlpha,
|
||||
const float2 i_UndisplacedXZ,
|
||||
const float i_PixelZ
|
||||
)
|
||||
{
|
||||
float2 worldXZ0 = i_UndisplacedXZ;
|
||||
float2 worldXZ1 = i_UndisplacedXZ;
|
||||
|
||||
#if (CREST_SHIFTING_ORIGIN != 0)
|
||||
// Apply tiled floating origin offset. Only needed if:
|
||||
// - _FoamScale is a non integer value
|
||||
// - _FoamScale is over 48
|
||||
worldXZ0 -= ShiftingOriginOffset(i_Texture, i_CascadeData0);
|
||||
worldXZ1 -= ShiftingOriginOffset(i_Texture, i_CascadeData1);
|
||||
#endif // CREST_SHIFTING_ORIGIN
|
||||
|
||||
// 0.25 is magic number found through tweaking.
|
||||
const float2 dd = float2(0.25 * i_PixelZ * i_Texture._texel, 0.0);
|
||||
const half whiteFoam_x = WhiteFoamTexture(i_Texture, i_FoamData, i_Feather, worldXZ0, worldXZ1, dd.xy, i_LodAlpha, i_CascadeData0);
|
||||
const half whiteFoam_z = WhiteFoamTexture(i_Texture, i_FoamData, i_Feather, worldXZ0, worldXZ1, dd.yx, i_LodAlpha, i_CascadeData0);
|
||||
|
||||
// Compute a foam normal - manually push in derivatives. If I used blend
|
||||
// smooths all the normals towards straight up when there is no foam.
|
||||
// Gets material slider into friendly range.
|
||||
const float magicStrengthFactor = 0.01;
|
||||
return magicStrengthFactor * i_NormalStrength * half2(whiteFoam_x - i_FoamAlbedo, whiteFoam_z - i_FoamAlbedo) / dd.x;
|
||||
}
|
||||
|
||||
half MultiScaleFoamAlbedo
|
||||
(
|
||||
const Flow i_Flow,
|
||||
const TiledTexture i_Texture,
|
||||
const half i_Feather,
|
||||
const half i_Foam,
|
||||
const Cascade i_CascadeData0,
|
||||
const Cascade i_CascadeData1,
|
||||
const half i_LodAlpha,
|
||||
const float2 i_UndisplacedXZ
|
||||
)
|
||||
{
|
||||
return MultiScaleFoamAlbedo
|
||||
(
|
||||
i_Texture,
|
||||
i_Feather,
|
||||
i_Foam,
|
||||
i_CascadeData0,
|
||||
i_CascadeData1,
|
||||
i_LodAlpha,
|
||||
i_UndisplacedXZ - i_Flow._Flow * i_Flow._Offset0
|
||||
) * i_Flow._Weight0 + MultiScaleFoamAlbedo
|
||||
(
|
||||
i_Texture,
|
||||
i_Feather,
|
||||
i_Foam,
|
||||
i_CascadeData0,
|
||||
i_CascadeData1,
|
||||
i_LodAlpha,
|
||||
i_UndisplacedXZ - i_Flow._Flow * i_Flow._Offset1
|
||||
) * i_Flow._Weight1;
|
||||
}
|
||||
|
||||
half2 MultiScaleFoamNormal
|
||||
(
|
||||
const Flow i_Flow,
|
||||
const TiledTexture i_Texture,
|
||||
const half i_Feather,
|
||||
const half i_NormalStrength,
|
||||
const half i_FoamData,
|
||||
const half i_FoamAlbedo,
|
||||
const Cascade i_CascadeData0,
|
||||
const Cascade i_CascadeData1,
|
||||
const half i_LodAlpha,
|
||||
const float2 i_UndisplacedXZ,
|
||||
const float i_PixelZ
|
||||
)
|
||||
{
|
||||
return MultiScaleFoamNormal
|
||||
(
|
||||
i_Texture,
|
||||
i_Feather,
|
||||
i_NormalStrength,
|
||||
i_FoamData,
|
||||
i_FoamAlbedo,
|
||||
i_CascadeData0,
|
||||
i_CascadeData1,
|
||||
i_LodAlpha,
|
||||
i_UndisplacedXZ - i_Flow._Flow * i_Flow._Offset0,
|
||||
i_PixelZ
|
||||
) * i_Flow._Weight0 + MultiScaleFoamNormal
|
||||
(
|
||||
i_Texture,
|
||||
i_Feather,
|
||||
i_NormalStrength,
|
||||
i_FoamData,
|
||||
i_FoamAlbedo,
|
||||
i_CascadeData0,
|
||||
i_CascadeData1,
|
||||
i_LodAlpha,
|
||||
i_UndisplacedXZ - i_Flow._Flow * i_Flow._Offset1,
|
||||
i_PixelZ
|
||||
) * i_Flow._Weight1;
|
||||
}
|
||||
|
||||
void ApplyFoamToSurface
|
||||
(
|
||||
half i_Foam,
|
||||
const half2 i_Normal,
|
||||
const half3 i_Albedo,
|
||||
const half i_Occlusion,
|
||||
const half i_Smoothness,
|
||||
const half i_Specular,
|
||||
const bool i_Underwater,
|
||||
inout half3 io_Albedo,
|
||||
inout half3 io_NormalWS,
|
||||
inout half3 io_Emission,
|
||||
inout half io_Occlusion,
|
||||
inout float io_Smoothness,
|
||||
inout half3 io_Specular
|
||||
)
|
||||
{
|
||||
// Apply foam to surface.
|
||||
io_Albedo = lerp(io_Albedo, i_Albedo, i_Foam);
|
||||
io_Emission *= 1.0 - i_Foam;
|
||||
io_Occlusion = lerp(io_Occlusion, i_Occlusion, i_Foam);
|
||||
io_Smoothness = lerp(io_Smoothness, i_Smoothness, i_Foam);
|
||||
io_NormalWS.xz -= i_Normal;
|
||||
io_NormalWS = normalize(io_NormalWS);
|
||||
|
||||
// Foam Transmission
|
||||
if (i_Underwater)
|
||||
{
|
||||
// Foam will be black when not facing the sun. This is a hacky way to have foam lit
|
||||
// as if it had transmission.
|
||||
// There is still ugliness around the edges. There will either be black or
|
||||
// incorrect reflections depending on the magic value.
|
||||
io_NormalWS.y *= i_Foam > 0.15 ? -1.0 : 1.0;
|
||||
io_Specular = lerp(io_Specular, i_Specular, i_Foam);
|
||||
}
|
||||
}
|
||||
|
||||
m_CrestNameSpaceEnd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 58f878eb932e14fb0b1d13173caa2857
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,644 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
// Guard against missing uniforms.
|
||||
#ifdef SHADERPASS
|
||||
|
||||
#define m_Properties \
|
||||
const float2 i_UndisplacedXZ, \
|
||||
const float i_LodAlpha, \
|
||||
const half i_WaterLevelOffset, \
|
||||
const float2 i_WaterLevelDerivatives, \
|
||||
const half2 i_Flow, \
|
||||
const half3 i_ViewDirectionWS, \
|
||||
const bool i_Facing, \
|
||||
const half3 i_SceneColor, \
|
||||
const float i_SceneDepthRaw, \
|
||||
const float4 i_ScreenPosition, \
|
||||
const float4 i_ScreenPositionRaw, \
|
||||
const float3 i_PositionWS, \
|
||||
const float3 i_PositionVS, \
|
||||
const float2 i_StaticLightMapUV, \
|
||||
out half3 o_Albedo, \
|
||||
out half3 o_NormalWS, \
|
||||
out half3 o_Specular, \
|
||||
out half3 o_Emission, \
|
||||
out half o_Smoothness, \
|
||||
out half o_Occlusion, \
|
||||
out half o_Alpha
|
||||
|
||||
// Guard against Shader Graph preview.
|
||||
#ifndef SHADERGRAPH_PREVIEW
|
||||
|
||||
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Shim.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/InputsDriven.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"
|
||||
|
||||
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Texture.hlsl"
|
||||
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Flow.hlsl"
|
||||
|
||||
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Utility/Lighting.hlsl"
|
||||
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Normal.hlsl"
|
||||
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Reflection.hlsl"
|
||||
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Refraction.hlsl"
|
||||
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Caustics.hlsl"
|
||||
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/VolumeLighting.hlsl"
|
||||
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Fresnel.hlsl"
|
||||
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Foam.hlsl"
|
||||
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Alpha.hlsl"
|
||||
|
||||
#if (CREST_PORTALS != 0)
|
||||
#include "Packages/com.waveharmonic.crest.portals/Runtime/Shaders/Library/Portals.hlsl"
|
||||
#endif
|
||||
|
||||
#if (CREST_SHADOWS_BUILT_IN_RENDER_PIPELINE != 0)
|
||||
#if CREST_BIRP
|
||||
#define SHADOWS_SPLIT_SPHERES 1
|
||||
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Utility/Legacy/Core.hlsl"
|
||||
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Utility/Legacy/Shadows.hlsl"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
bool _Crest_DrawBoundaryXZ;
|
||||
float4 _Crest_BoundaryXZ;
|
||||
|
||||
m_CrestNameSpace
|
||||
|
||||
static const TiledTexture _Crest_NormalMapTiledTexture =
|
||||
TiledTexture::Make(_Crest_NormalMapTexture, sampler_Crest_NormalMapTexture, _Crest_NormalMapTexture_TexelSize, _Crest_NormalMapScale, _Crest_NormalMapScrollSpeed);
|
||||
|
||||
static const TiledTexture _Crest_FoamTiledTexture =
|
||||
TiledTexture::Make(_Crest_FoamTexture, sampler_Crest_FoamTexture, _Crest_FoamTexture_TexelSize, _Crest_FoamScale, _Crest_FoamScrollSpeed);
|
||||
|
||||
static const TiledTexture _Crest_CausticsTiledTexture =
|
||||
TiledTexture::Make(_Crest_CausticsTexture, sampler_Crest_CausticsTexture, _Crest_CausticsTexture_TexelSize, _Crest_CausticsTextureScale, _Crest_CausticsScrollSpeed);
|
||||
static const TiledTexture _Crest_CausticsDistortionTiledTexture =
|
||||
TiledTexture::Make(_Crest_CausticsDistortionTexture, sampler_Crest_CausticsDistortionTexture, _Crest_CausticsDistortionTexture_TexelSize, _Crest_CausticsDistortionScale, 1.0);
|
||||
|
||||
void Fragment(m_Properties)
|
||||
{
|
||||
o_Albedo = 0.0;
|
||||
o_NormalWS = half3(0.0, 1.0, 0.0);
|
||||
o_Specular = 0.0;
|
||||
o_Emission = 0.0;
|
||||
o_Smoothness = 0.7;
|
||||
o_Occlusion = 1.0;
|
||||
o_Alpha = 1.0;
|
||||
|
||||
|
||||
// Editor only. There is no defined editor symbol.
|
||||
if (_Crest_DrawBoundaryXZ)
|
||||
{
|
||||
const float2 p = abs(i_PositionWS.xz - _Crest_BoundaryXZ.xy);
|
||||
const float2 s = _Crest_BoundaryXZ.zw * 0.5;
|
||||
if ((p.x > s.x && p.x < s.x + 1.0 && p.y < s.y + 1.0) || (p.y > s.y && p.y < s.y + 1.0 && p.x < s.x + 1.0))
|
||||
{
|
||||
o_Emission = half3(1.0, 0.0, 1.0);
|
||||
#if CREST_HDRP
|
||||
o_Emission /= GetCurrentExposureMultiplier();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
const bool underwater = IsUnderwater(i_Facing, g_Crest_ForceUnderwater);
|
||||
|
||||
// TODO: Should we use PosToSIs or check for overflow?
|
||||
float slice0 = _Crest_LodIndex;
|
||||
float slice1 = _Crest_LodIndex + 1;
|
||||
|
||||
#ifdef CREST_FLOW_ON
|
||||
const Flow flow = Flow::Make(i_Flow, g_Crest_Time);
|
||||
#endif
|
||||
|
||||
const Cascade cascade0 = Cascade::Make(slice0);
|
||||
const Cascade cascade1 = Cascade::Make(slice1);
|
||||
|
||||
float sceneRawZ = i_SceneDepthRaw;
|
||||
|
||||
#if (CREST_PORTALS != 0)
|
||||
#ifndef CREST_SHADOWPASS
|
||||
#if _ALPHATEST_ON
|
||||
if (m_CrestPortal)
|
||||
{
|
||||
const float pixelRawZ = i_ScreenPositionRaw.z / i_ScreenPositionRaw.w;
|
||||
if (OutsideOfPortal(i_ScreenPosition.xy, pixelRawZ, sceneRawZ))
|
||||
{
|
||||
o_Alpha = 0.0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
float sceneZ = Utility::CrestLinearEyeDepth(sceneRawZ);
|
||||
float pixelZ = -i_PositionVS.z;
|
||||
|
||||
const bool isLastLod = _Crest_LodIndex == (uint)g_Crest_LodCount - 1;
|
||||
const float weight0 = (1.0 - i_LodAlpha) * cascade0._Weight;
|
||||
const float weight1 = (1.0 - weight0) * cascade1._Weight;
|
||||
|
||||
// Data that fades towards the edge.
|
||||
half foam = 0.0; half _determinant = 0.0; half4 albedo = 0.0; half2 shadow = 0.0;
|
||||
if (weight0 > m_CrestSampleLodThreshold)
|
||||
{
|
||||
Cascade::MakeAnimatedWaves(slice0).SampleNormals(i_UndisplacedXZ, weight0, o_NormalWS.xz, _determinant);
|
||||
|
||||
if (_Crest_FoamEnabled)
|
||||
{
|
||||
Cascade::MakeFoam(slice0).SampleFoam(i_UndisplacedXZ, weight0, foam);
|
||||
}
|
||||
|
||||
if (_Crest_AlbedoEnabled)
|
||||
{
|
||||
Cascade::MakeAlbedo(slice0).SampleAlbedo(i_UndisplacedXZ, weight0, albedo);
|
||||
}
|
||||
|
||||
if (_Crest_ShadowsEnabled)
|
||||
{
|
||||
Cascade::MakeShadow(slice0).SampleShadow(i_PositionWS.xz, weight0, shadow);
|
||||
}
|
||||
}
|
||||
|
||||
if (weight1 > m_CrestSampleLodThreshold)
|
||||
{
|
||||
Cascade::MakeAnimatedWaves(slice1).SampleNormals(i_UndisplacedXZ, weight1, o_NormalWS.xz, _determinant);
|
||||
|
||||
if (_Crest_FoamEnabled)
|
||||
{
|
||||
Cascade::MakeFoam(slice1).SampleFoam(i_UndisplacedXZ, weight1, foam);
|
||||
}
|
||||
|
||||
if (_Crest_AlbedoEnabled)
|
||||
{
|
||||
Cascade::MakeAlbedo(slice1).SampleAlbedo(i_UndisplacedXZ, weight1, albedo);
|
||||
}
|
||||
|
||||
if (_Crest_ShadowsEnabled)
|
||||
{
|
||||
Cascade::MakeShadow(slice1).SampleShadow(i_PositionWS.xz, weight1, shadow);
|
||||
}
|
||||
}
|
||||
|
||||
// Invert so shadows are black as we normally multiply this by lighting.
|
||||
shadow = 1.0 - shadow;
|
||||
|
||||
// Data that displays to the edge.
|
||||
// The default simulation value has been written to the border of the last slice.
|
||||
half3 absorption = 0.0; half3 scattering = 0.0;
|
||||
{
|
||||
const float weight0 = (1.0 - (isLastLod ? 0.0 : i_LodAlpha)) * cascade0._Weight;
|
||||
const float weight1 = (1.0 - weight0) * cascade1._Weight;
|
||||
|
||||
if (weight0 > m_CrestSampleLodThreshold)
|
||||
{
|
||||
if (g_Crest_SampleScatteringSimulation)
|
||||
{
|
||||
Cascade::MakeScattering(slice0).SampleScattering(i_UndisplacedXZ, weight0, scattering);
|
||||
}
|
||||
|
||||
if (g_Crest_SampleAbsorptionSimulation)
|
||||
{
|
||||
Cascade::MakeAbsorption(slice0).SampleAbsorption(i_UndisplacedXZ, weight0, absorption);
|
||||
}
|
||||
}
|
||||
|
||||
if (weight1 > m_CrestSampleLodThreshold)
|
||||
{
|
||||
if (g_Crest_SampleScatteringSimulation)
|
||||
{
|
||||
Cascade::MakeScattering(slice1).SampleScattering(i_UndisplacedXZ, weight1, scattering);
|
||||
}
|
||||
|
||||
if (g_Crest_SampleAbsorptionSimulation)
|
||||
{
|
||||
Cascade::MakeAbsorption(slice1).SampleAbsorption(i_UndisplacedXZ, weight1, absorption);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_Crest_SampleScatteringSimulation)
|
||||
{
|
||||
scattering = _Crest_Scattering.xyz;
|
||||
}
|
||||
|
||||
if (!g_Crest_SampleAbsorptionSimulation)
|
||||
{
|
||||
absorption = _Crest_Absorption.xyz;
|
||||
}
|
||||
|
||||
// Determinant needs to be one when no waves.
|
||||
if (isLastLod)
|
||||
{
|
||||
_determinant += 1.0 - weight0;
|
||||
}
|
||||
|
||||
// Normal.
|
||||
{
|
||||
WaterNormal
|
||||
(
|
||||
i_WaterLevelDerivatives,
|
||||
i_ViewDirectionWS,
|
||||
_Crest_MinimumReflectionDirectionY,
|
||||
underwater,
|
||||
o_NormalWS
|
||||
);
|
||||
|
||||
if (_Crest_NormalMapEnabled)
|
||||
{
|
||||
o_NormalWS.xz += SampleNormalMaps
|
||||
(
|
||||
#ifdef CREST_FLOW_ON
|
||||
flow,
|
||||
#endif
|
||||
_Crest_NormalMapTiledTexture,
|
||||
_Crest_NormalMapStrength,
|
||||
i_UndisplacedXZ,
|
||||
i_LodAlpha,
|
||||
cascade0
|
||||
);
|
||||
}
|
||||
|
||||
o_NormalWS = normalize(o_NormalWS);
|
||||
|
||||
o_NormalWS.xz *= _Crest_NormalsStrengthOverall;
|
||||
o_NormalWS.y = lerp(1.0, o_NormalWS.y, _Crest_NormalsStrengthOverall);
|
||||
|
||||
if (underwater)
|
||||
{
|
||||
// Flip when underwater.
|
||||
o_NormalWS.xyz *= -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
// Default for opaque render type.
|
||||
float sceneDistance = 1000.0;
|
||||
float3 scenePositionWS = 0.0;
|
||||
|
||||
half3 ambientLight = 0.0;
|
||||
AmbientLight
|
||||
(
|
||||
ambientLight
|
||||
);
|
||||
|
||||
float3 lightIntensity = 0.0;
|
||||
half3 lightDirection = 0.0;
|
||||
|
||||
PrimaryLight
|
||||
(
|
||||
i_PositionWS,
|
||||
lightIntensity,
|
||||
lightDirection
|
||||
);
|
||||
|
||||
half3 additionalLight = AdditionalLighting(i_PositionWS, i_ScreenPositionRaw, i_StaticLightMapUV);
|
||||
|
||||
#if d_Crest_ReceiveShadowsTransparent
|
||||
// Sample shadow maps.
|
||||
float4 shadowCoord = GET_SHADOW_COORDINATES(float4(i_PositionWS, 1.0));
|
||||
half shadows = UNITY_SAMPLE_SHADOW(_ShadowMapTexture, shadowCoord);
|
||||
shadows = lerp(_LightShadowData.r, 1.0, shadows);
|
||||
shadows = min(shadow.y, shadows);
|
||||
#endif
|
||||
|
||||
#if d_Transparent
|
||||
bool caustics;
|
||||
RefractedScene
|
||||
(
|
||||
_Crest_RefractionStrength,
|
||||
o_NormalWS,
|
||||
i_ScreenPosition.xy,
|
||||
pixelZ,
|
||||
i_SceneColor,
|
||||
sceneZ,
|
||||
sceneRawZ,
|
||||
underwater,
|
||||
o_Emission,
|
||||
sceneDistance,
|
||||
scenePositionWS,
|
||||
caustics
|
||||
);
|
||||
#endif
|
||||
|
||||
float refractedSeaLevel = 0;
|
||||
float3 refractedSurfacePosition = 0;
|
||||
if (!underwater)
|
||||
{
|
||||
// Sample larger slice to avoid the first slice.
|
||||
float4 displacement = Cascade::MakeAnimatedWaves(slice1).Sample(scenePositionWS.xz);
|
||||
refractedSeaLevel = g_Crest_WaterCenter.y + displacement.w;
|
||||
refractedSurfacePosition = displacement.xyz;
|
||||
refractedSurfacePosition.y += refractedSeaLevel;
|
||||
}
|
||||
|
||||
// Out-scattering.
|
||||
if (!underwater)
|
||||
{
|
||||
// Account for average extinction of light as it travels down through volume. Assume flat water as anything else would be expensive.
|
||||
half3 extinction = absorption.xyz + scattering.xyz;
|
||||
o_Emission *= exp(-extinction * max(0.0, refractedSeaLevel - scenePositionWS.y));
|
||||
}
|
||||
|
||||
#if d_Transparent
|
||||
// Caustics
|
||||
if (_Crest_CausticsEnabled && !underwater && caustics)
|
||||
{
|
||||
float3 position = scenePositionWS;
|
||||
#if CREST_BIRP
|
||||
position = float3(i_ScreenPosition.xy * _ScreenSize.xy, 0);
|
||||
#endif
|
||||
|
||||
half lightOcclusion = PrimaryLightShadows(position);
|
||||
|
||||
half blur = 0.0;
|
||||
#ifdef CREST_FLOW_ON
|
||||
blur = _Crest_CausticsMotionBlur;
|
||||
#endif
|
||||
|
||||
o_Emission *= Caustics
|
||||
(
|
||||
#ifdef CREST_FLOW_ON
|
||||
flow,
|
||||
#endif
|
||||
scenePositionWS,
|
||||
refractedSurfacePosition.y,
|
||||
lightIntensity,
|
||||
lightDirection,
|
||||
lightOcclusion,
|
||||
sceneDistance,
|
||||
_Crest_CausticsTiledTexture,
|
||||
_Crest_CausticsTextureAverage,
|
||||
_Crest_CausticsStrength,
|
||||
_Crest_CausticsFocalDepth,
|
||||
_Crest_CausticsDepthOfField,
|
||||
_Crest_CausticsDistortionTiledTexture,
|
||||
_Crest_CausticsDistortionStrength,
|
||||
blur,
|
||||
underwater
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
half3 sss = 0.0;
|
||||
|
||||
if (_Crest_SSSEnabled)
|
||||
{
|
||||
sss = PinchSSS
|
||||
(
|
||||
_determinant,
|
||||
_Crest_SSSPinchMinimum,
|
||||
_Crest_SSSPinchMaximum,
|
||||
_Crest_SSSPinchFalloff,
|
||||
_Crest_SSSIntensity,
|
||||
lightDirection,
|
||||
_Crest_SSSDirectionalFalloff,
|
||||
i_ViewDirectionWS
|
||||
);
|
||||
}
|
||||
|
||||
// Volume Lighting
|
||||
half3 volumeLight = 0.0;
|
||||
half3 volumeOpacity = 0.0;
|
||||
VolumeLighting
|
||||
(
|
||||
absorption,
|
||||
scattering,
|
||||
_Crest_Anisotropy,
|
||||
shadow.x,
|
||||
i_ViewDirectionWS,
|
||||
ambientLight,
|
||||
lightDirection,
|
||||
lightIntensity,
|
||||
additionalLight,
|
||||
_Crest_AmbientTerm,
|
||||
_Crest_DirectTerm,
|
||||
sceneDistance,
|
||||
sss,
|
||||
_Crest_ShadowsAffectsAmbientFactor,
|
||||
volumeLight,
|
||||
volumeOpacity
|
||||
);
|
||||
|
||||
// Fresnel
|
||||
float reflected = 0.0;
|
||||
float transmitted = 0.0;
|
||||
{
|
||||
ApplyFresnel
|
||||
(
|
||||
i_ViewDirectionWS,
|
||||
o_NormalWS,
|
||||
underwater,
|
||||
1.0, // air
|
||||
_Crest_RefractiveIndexOfWater,
|
||||
_Crest_TotalInternalReflectionIntensity,
|
||||
transmitted,
|
||||
reflected
|
||||
);
|
||||
|
||||
if (underwater)
|
||||
{
|
||||
o_Emission *= transmitted;
|
||||
o_Emission += volumeLight * reflected;
|
||||
}
|
||||
else
|
||||
{
|
||||
o_Emission *= 1.0 - volumeOpacity;
|
||||
o_Emission += volumeLight * volumeOpacity;
|
||||
o_Emission *= transmitted;
|
||||
}
|
||||
}
|
||||
|
||||
// Specular
|
||||
{
|
||||
o_Specular = _Crest_Specular * reflected * shadow.y;
|
||||
}
|
||||
|
||||
// Smoothness
|
||||
{
|
||||
// Vary smoothness by distance.
|
||||
o_Smoothness = lerp(_Crest_Smoothness, _Crest_SmoothnessFar, pow(saturate(pixelZ / _Crest_SmoothnessFarDistance), _Crest_SmoothnessFalloff));
|
||||
}
|
||||
|
||||
// Occlusion
|
||||
{
|
||||
o_Occlusion = underwater ? _Crest_OcclusionUnderwater : _Crest_Occlusion;
|
||||
}
|
||||
|
||||
// Planar Reflections
|
||||
if (_Crest_PlanarReflectionsEnabled)
|
||||
{
|
||||
half4 reflection = PlanarReflection
|
||||
(
|
||||
_Crest_ReflectionTexture,
|
||||
sampler_Crest_ReflectionTexture,
|
||||
_Crest_PlanarReflectionsIntensity,
|
||||
o_Smoothness,
|
||||
_Crest_PlanarReflectionsRoughness,
|
||||
o_NormalWS,
|
||||
_Crest_PlanarReflectionsDistortion,
|
||||
i_ViewDirectionWS,
|
||||
i_ScreenPosition.xy,
|
||||
underwater
|
||||
);
|
||||
|
||||
half alpha = reflection.a;
|
||||
o_Emission = lerp(o_Emission, reflection.rgb, alpha * reflected * o_Occlusion);
|
||||
// Override reflections with planar reflections.
|
||||
// Results are darker than Unity's.
|
||||
o_Occlusion *= 1.0 - alpha;
|
||||
}
|
||||
|
||||
// Foam
|
||||
if (_Crest_FoamEnabled)
|
||||
{
|
||||
half albedo = MultiScaleFoamAlbedo
|
||||
(
|
||||
#ifdef CREST_FLOW_ON
|
||||
flow,
|
||||
#endif
|
||||
_Crest_FoamTiledTexture,
|
||||
_Crest_FoamFeather,
|
||||
foam,
|
||||
cascade0,
|
||||
cascade1,
|
||||
i_LodAlpha,
|
||||
i_UndisplacedXZ
|
||||
);
|
||||
|
||||
half2 normal = MultiScaleFoamNormal
|
||||
(
|
||||
#ifdef CREST_FLOW_ON
|
||||
flow,
|
||||
#endif
|
||||
_Crest_FoamTiledTexture,
|
||||
_Crest_FoamFeather,
|
||||
_Crest_FoamNormalStrength,
|
||||
foam,
|
||||
albedo,
|
||||
cascade0,
|
||||
cascade1,
|
||||
i_LodAlpha,
|
||||
i_UndisplacedXZ,
|
||||
pixelZ
|
||||
);
|
||||
|
||||
half3 intensity = _Crest_FoamIntensityAlbedo;
|
||||
|
||||
#if d_Crest_ReceiveShadowsTransparent
|
||||
// @HACK: Scale intensity as BIRP does not support shadows for transparent objects.
|
||||
intensity = max(_Crest_FoamIntensityAlbedo * saturate(ShadeSH9(float4(o_NormalWS, 1.0))), _Crest_FoamIntensityAlbedo * shadows);
|
||||
#endif
|
||||
|
||||
ApplyFoamToSurface
|
||||
(
|
||||
albedo,
|
||||
normal,
|
||||
intensity,
|
||||
_Crest_Occlusion,
|
||||
_Crest_FoamSmoothness,
|
||||
_Crest_Specular,
|
||||
underwater,
|
||||
o_Albedo,
|
||||
o_NormalWS,
|
||||
o_Emission,
|
||||
o_Occlusion,
|
||||
o_Smoothness,
|
||||
o_Specular
|
||||
);
|
||||
|
||||
// We will use this for shadow casting.
|
||||
foam = albedo;
|
||||
}
|
||||
|
||||
// Albedo
|
||||
if (_Crest_AlbedoEnabled)
|
||||
{
|
||||
const float foamMask = _Crest_AlbedoIgnoreFoam ? (1.0 - saturate(foam)) : 1.0;
|
||||
o_Albedo = lerp(o_Albedo, albedo.rgb, albedo.a * foamMask);
|
||||
o_Emission *= 1.0 - albedo.a * foamMask;
|
||||
}
|
||||
|
||||
// Alpha
|
||||
{
|
||||
#ifndef CREST_SHADOWPASS
|
||||
#if d_Transparent
|
||||
// Feather at intersection. Cannot be used for shadows since depth is not available.
|
||||
o_Alpha = saturate((sceneZ - pixelZ) / 0.2);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// This keyword works for all RPs despite BIRP having prefixes in serialised data.
|
||||
#if _ALPHATEST_ON
|
||||
#if CREST_SHADOWPASS
|
||||
o_Alpha = max(foam, albedo.a) - _Crest_ShadowCasterThreshold;
|
||||
#endif
|
||||
|
||||
// Add 0.5 bias for LOD blending and texel resolution correction. This will help to
|
||||
// tighten and smooth clipped edges.
|
||||
o_Alpha -= ClipSurface(i_PositionWS.xz) > 0.5 ? 2.0 : 0.0;
|
||||
#endif // _ALPHATEST_ON
|
||||
|
||||
// Specular in HDRP is still affected outside the 0-1 alpha range.
|
||||
o_Alpha = min(o_Alpha, 1.0);
|
||||
}
|
||||
|
||||
#if d_Crest_ReceiveShadowsTransparent
|
||||
// @HACK: Dull highlights as BIRP does not support shadows for transparent objects.
|
||||
o_Smoothness *= lerp(1, shadows, foam * 100);
|
||||
// @FIXME: 0.2 to difference when high. Likely incorrect shadow sampling.
|
||||
o_Specular = shadows < 0.2 ? 1.0 - max(shadows, 0.3) : o_Specular;
|
||||
#endif
|
||||
}
|
||||
|
||||
m_CrestNameSpaceEnd
|
||||
|
||||
#endif // SHADERGRAPH_PREVIEW
|
||||
|
||||
void Fragment_float(m_Properties)
|
||||
{
|
||||
#if SHADERGRAPH_PREVIEW
|
||||
o_Albedo = 0.0;
|
||||
o_NormalWS = half3(0.0, 1.0, 0.0);
|
||||
o_Specular = 0.0;
|
||||
o_Emission = 0.0;
|
||||
o_Smoothness = 0.7;
|
||||
o_Occlusion = 1.0;
|
||||
o_Alpha = 1.0;
|
||||
#else // SHADERGRAPH_PREVIEW
|
||||
m_Crest::Fragment
|
||||
(
|
||||
i_UndisplacedXZ,
|
||||
i_LodAlpha,
|
||||
i_WaterLevelOffset,
|
||||
i_WaterLevelDerivatives,
|
||||
i_Flow,
|
||||
i_ViewDirectionWS,
|
||||
i_Facing,
|
||||
i_SceneColor,
|
||||
i_SceneDepthRaw,
|
||||
i_ScreenPosition,
|
||||
i_ScreenPositionRaw,
|
||||
i_PositionWS,
|
||||
i_PositionVS,
|
||||
i_StaticLightMapUV,
|
||||
o_Albedo,
|
||||
o_NormalWS,
|
||||
o_Specular,
|
||||
o_Emission,
|
||||
o_Smoothness,
|
||||
o_Occlusion,
|
||||
o_Alpha
|
||||
);
|
||||
#endif // SHADERGRAPH_PREVIEW
|
||||
}
|
||||
|
||||
#undef m_Properties
|
||||
|
||||
#endif // SHADERPASS
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fdafd40ae20374db88e293739fad1854
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,83 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
#ifndef CREST_WATER_FRESNEL_H
|
||||
#define CREST_WATER_FRESNEL_H
|
||||
|
||||
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Macros.hlsl"
|
||||
|
||||
m_CrestNameSpace
|
||||
|
||||
float CalculateFresnelReflectionCoefficient(const float i_CosineTheta, const float i_RefractiveIndexOfAir, const float i_RefractiveIndexOfWater)
|
||||
{
|
||||
// Fresnel calculated using Schlick's approximation.
|
||||
// See: http://www.cs.virginia.edu/~jdl/bib/appearance/analytic%20models/schlick94b.pdf
|
||||
// Reflectance at facing angle.
|
||||
float R_0 = (i_RefractiveIndexOfAir - i_RefractiveIndexOfWater) / (i_RefractiveIndexOfAir + i_RefractiveIndexOfWater);
|
||||
R_0 *= R_0;
|
||||
const float R_theta = R_0 + (1.0 - R_0) * pow(max(0., 1.0 - i_CosineTheta), 5.0);
|
||||
return R_theta;
|
||||
}
|
||||
|
||||
void ApplyReflectionUnderwater(
|
||||
const half3 i_ViewDirectionWS,
|
||||
const half3 i_NormalWS,
|
||||
const float i_RefractiveIndexOfAir,
|
||||
const float i_RefractiveIndexOfWater,
|
||||
out float o_LightTransmitted,
|
||||
out float o_LightReflected
|
||||
) {
|
||||
// The the angle of outgoing light from water's surface (whether refracted form outside or internally reflected).
|
||||
const float cosOutgoingAngle = max(dot(i_NormalWS, i_ViewDirectionWS), 0.);
|
||||
|
||||
// Calculate the amount of light transmitted from the sky (o_LightTransmitted).
|
||||
{
|
||||
// Have to calculate the incident angle of incoming light to water.
|
||||
// Surface based on how it would be refracted so as to hit the camera.
|
||||
const float cosIncomingAngle = cos(asin(clamp((i_RefractiveIndexOfWater * sin(acos(cosOutgoingAngle))) / i_RefractiveIndexOfAir, -1.0, 1.0)));
|
||||
const float reflectionCoefficient = CalculateFresnelReflectionCoefficient(cosIncomingAngle, i_RefractiveIndexOfAir, i_RefractiveIndexOfWater);
|
||||
o_LightTransmitted = (1.0 - reflectionCoefficient);
|
||||
o_LightTransmitted = max(o_LightTransmitted, 0.0);
|
||||
}
|
||||
|
||||
// Calculate the amount of light reflected from below the water.
|
||||
{
|
||||
// Angle of incident is angle of reflection.
|
||||
const float cosIncomingAngle = cosOutgoingAngle;
|
||||
const float reflectionCoefficient = CalculateFresnelReflectionCoefficient(cosIncomingAngle, i_RefractiveIndexOfAir, i_RefractiveIndexOfWater);
|
||||
o_LightReflected = reflectionCoefficient;
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyFresnel
|
||||
(
|
||||
const half3 i_ViewDirectionWS,
|
||||
const half3 i_NormalWS,
|
||||
const bool i_IsUnderwater,
|
||||
const float i_RefractiveIndexOfAir,
|
||||
const float i_RefractiveIndexOfWater,
|
||||
const float i_TirIntensity,
|
||||
out float o_LightTransmitted,
|
||||
out float o_LightReflected
|
||||
)
|
||||
{
|
||||
o_LightTransmitted = 1.0;
|
||||
|
||||
if (i_IsUnderwater)
|
||||
{
|
||||
ApplyReflectionUnderwater(i_ViewDirectionWS, i_NormalWS, i_RefractiveIndexOfAir, i_RefractiveIndexOfWater, o_LightTransmitted, o_LightReflected);
|
||||
// Limit how strong TIR is. Not sure if this is the best way but it seems to work gracefully.
|
||||
o_LightTransmitted = max(o_LightTransmitted, 1.0 - i_TirIntensity);
|
||||
o_LightReflected = min(o_LightReflected, i_TirIntensity);
|
||||
}
|
||||
else
|
||||
{
|
||||
const float cosAngle = max(dot(i_NormalWS, i_ViewDirectionWS), 0.0);
|
||||
// Hardcode water IOR for above surface.
|
||||
o_LightReflected = CalculateFresnelReflectionCoefficient(cosAngle, i_RefractiveIndexOfAir, 1.33);
|
||||
}
|
||||
}
|
||||
|
||||
m_CrestNameSpaceEnd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7e2e3d8f8fe32492583d087ad2add952
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,75 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
#ifndef CREST_WATER_VERT_HELPERS_H
|
||||
#define CREST_WATER_VERT_HELPERS_H
|
||||
|
||||
#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/Cascade.hlsl"
|
||||
|
||||
m_CrestNameSpace
|
||||
|
||||
// i_meshScaleAlpha is passed in as it is provided per tile and is set only for LOD0
|
||||
float ComputeLodAlpha(float3 i_worldPos, float i_meshScaleAlpha, in const Cascade i_cascadeData0)
|
||||
{
|
||||
// taxicab distance from water center drives LOD transitions
|
||||
float2 offsetFromCenter = abs(float2(i_worldPos.x - g_Crest_WaterCenter.x, i_worldPos.z - g_Crest_WaterCenter.z));
|
||||
float taxicab_norm = max(offsetFromCenter.x, offsetFromCenter.y);
|
||||
|
||||
// interpolation factor to next lod (lower density / higher sampling period)
|
||||
// TODO - pass this in, and then make a node to provide it automatically
|
||||
float lodAlpha = taxicab_norm / i_cascadeData0._Scale - 1.0;
|
||||
|
||||
// LOD alpha is remapped to ensure patches weld together properly. Patches can vary significantly in shape (with
|
||||
// strips added and removed), and this variance depends on the base vertex density of the mesh, as this defines the
|
||||
// strip width.
|
||||
lodAlpha = max((lodAlpha - g_Crest_LodAlphaBlackPointFade) / g_Crest_LodAlphaBlackPointWhitePointFade, 0.);
|
||||
|
||||
// blend out lod0 when viewpoint gains altitude
|
||||
lodAlpha = min(lodAlpha + i_meshScaleAlpha, 1.);
|
||||
|
||||
#if _DEBUGDISABLESMOOTHLOD_ON
|
||||
lodAlpha = 0.;
|
||||
#endif
|
||||
|
||||
return lodAlpha;
|
||||
}
|
||||
|
||||
void SnapAndTransitionVertLayout(in const float4x4 i_objectMatrix, in const float i_meshScaleAlpha, in const Cascade i_cascadeData0, in const float i_geometryGridSize, inout float3 io_worldPos, out float o_lodAlpha)
|
||||
{
|
||||
const float GRID_SIZE_2 = 2.0 * i_geometryGridSize, GRID_SIZE_4 = 4.0 * i_geometryGridSize;
|
||||
|
||||
// snap the verts to the grid
|
||||
// The snap size should be twice the original size to keep the shape of the eight triangles (otherwise the edge layout changes).
|
||||
float2 objectPosXZWS = i_objectMatrix._m03_m23;
|
||||
|
||||
// Relative world space - add camera pos to get back out to world. Would be nice if we could operate in RWS..
|
||||
#if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0)
|
||||
objectPosXZWS += _WorldSpaceCameraPos.xz;
|
||||
#endif
|
||||
|
||||
io_worldPos.xz -= frac(objectPosXZWS / GRID_SIZE_2) * GRID_SIZE_2; // caution - sign of frac might change in non-hlsl shaders
|
||||
|
||||
// compute lod transition alpha
|
||||
o_lodAlpha = ComputeLodAlpha(io_worldPos, i_meshScaleAlpha, i_cascadeData0);
|
||||
|
||||
// now smoothly transition vert layouts between lod levels - move interior verts inwards towards center
|
||||
float2 m = frac(io_worldPos.xz / GRID_SIZE_4); // this always returns positive
|
||||
float2 offset = m - 0.5;
|
||||
// Check if vert is within one square from the center point which the verts move towards. the verts that need moving
|
||||
// inwards should have a radius of 0.25, whereas the outer ring of verts will have radius 0.5. Pick half way between
|
||||
// to give max leeway for numerical robustness.
|
||||
const float minRadius = 0.375;
|
||||
if (abs(offset.x) < minRadius) io_worldPos.x += offset.x * o_lodAlpha * GRID_SIZE_4;
|
||||
if (abs(offset.y) < minRadius) io_worldPos.z += offset.y * o_lodAlpha * GRID_SIZE_4;
|
||||
}
|
||||
|
||||
void SnapAndTransitionVertLayout(in const float i_meshScaleAlpha, in const Cascade i_cascadeData0, in const float i_geometryGridSize, inout float3 io_worldPos, out float o_lodAlpha)
|
||||
{
|
||||
SnapAndTransitionVertLayout(UNITY_MATRIX_M, i_meshScaleAlpha, i_cascadeData0, i_geometryGridSize, io_worldPos, o_lodAlpha);
|
||||
}
|
||||
|
||||
m_CrestNameSpaceEnd
|
||||
|
||||
#endif // CREST_WATER_VERT_HELPERS_H
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1917cef0dc0904e92aeeb267b5543b49
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,123 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
#ifndef CREST_WATER_NORMAL_H
|
||||
#define CREST_WATER_NORMAL_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/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
|
||||
|
||||
half2 SampleNormalMaps
|
||||
(
|
||||
const TiledTexture i_NormalMap,
|
||||
const half i_Strength,
|
||||
const float2 i_UndisplacedXZ,
|
||||
const float i_LodAlpha,
|
||||
const Cascade i_CascadeData
|
||||
)
|
||||
{
|
||||
float2 worldXZUndisplaced = i_UndisplacedXZ;
|
||||
|
||||
#if (CREST_SHIFTING_ORIGIN != 0)
|
||||
// Apply tiled floating origin offset. Always needed.
|
||||
worldXZUndisplaced -= ShiftingOriginOffset(i_NormalMap, i_CascadeData);
|
||||
#endif
|
||||
|
||||
const float2 v0 = float2(0.94, 0.34), v1 = float2(-0.85, -0.53);
|
||||
float scale = i_NormalMap._scale * i_CascadeData._Scale / 10.0;
|
||||
const float spdmulL = _Crest_ChunkNormalScrollSpeed.x * i_NormalMap._speed;
|
||||
half2 norm =
|
||||
UnpackNormal(i_NormalMap.Sample((worldXZUndisplaced + v0 * g_Crest_Time * spdmulL) / scale)).xy +
|
||||
UnpackNormal(i_NormalMap.Sample((worldXZUndisplaced + v1 * g_Crest_Time * spdmulL) / scale)).xy;
|
||||
|
||||
// blend in next higher scale of normals to obtain continuity
|
||||
const half nblend = i_LodAlpha * _Crest_ChunkFarNormalsWeight;
|
||||
if (nblend > 0.001)
|
||||
{
|
||||
// next lod level
|
||||
scale *= 2.0;
|
||||
const float spdmulH = _Crest_ChunkNormalScrollSpeed.y * i_NormalMap._speed;
|
||||
norm = lerp(norm,
|
||||
UnpackNormal(i_NormalMap.Sample((worldXZUndisplaced + v0 * g_Crest_Time * spdmulH) / scale)).xy +
|
||||
UnpackNormal(i_NormalMap.Sample((worldXZUndisplaced + v1 * g_Crest_Time * spdmulH) / scale)).xy,
|
||||
nblend);
|
||||
}
|
||||
|
||||
// approximate combine of normals. would be better if normals applied in local frame.
|
||||
return i_Strength * norm;
|
||||
}
|
||||
|
||||
half2 SampleNormalMaps
|
||||
(
|
||||
const Flow i_Flow,
|
||||
const TiledTexture i_NormalMap,
|
||||
const half i_Strength,
|
||||
const float2 i_UndisplacedXZ,
|
||||
const float i_LodAlpha,
|
||||
const Cascade i_CascadeData
|
||||
)
|
||||
{
|
||||
return SampleNormalMaps
|
||||
(
|
||||
i_NormalMap,
|
||||
i_Strength,
|
||||
i_UndisplacedXZ - i_Flow._Flow * (i_Flow._Offset0 - i_Flow._Period * 0.5),
|
||||
i_LodAlpha,
|
||||
i_CascadeData
|
||||
) * i_Flow._Weight0 + SampleNormalMaps
|
||||
(
|
||||
i_NormalMap,
|
||||
i_Strength,
|
||||
i_UndisplacedXZ - i_Flow._Flow * (i_Flow._Offset1 - i_Flow._Period * 0.5),
|
||||
i_LodAlpha,
|
||||
i_CascadeData
|
||||
) * i_Flow._Weight1;
|
||||
}
|
||||
|
||||
void WaterNormal
|
||||
(
|
||||
const float2 i_WaterLevelDerivatives,
|
||||
const half3 i_ViewDirectionWS,
|
||||
const half i_MinimumReflectionDirectionY,
|
||||
const bool i_Underwater,
|
||||
inout half3 io_NormalWS
|
||||
)
|
||||
{
|
||||
// Account for water level changes which change angle of water surface, impacting normal.
|
||||
io_NormalWS.xz += -i_WaterLevelDerivatives;
|
||||
|
||||
// Finalise normal
|
||||
io_NormalWS = normalize(io_NormalWS);
|
||||
|
||||
if (i_Underwater)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Limit how close to horizontal reflection ray can get, useful to avoid unsightly below-horizon reflections.
|
||||
{
|
||||
float3 refl = reflect(-i_ViewDirectionWS, io_NormalWS);
|
||||
if (refl.y < i_MinimumReflectionDirectionY)
|
||||
{
|
||||
// Find the normal that keeps the reflection direction above the horizon. Compute
|
||||
// the reflection dir that does work, normalize it, and then normal is half vector
|
||||
// between this good reflection direction and view direction.
|
||||
float3 FL = refl;
|
||||
FL.y = i_MinimumReflectionDirectionY;
|
||||
FL = normalize(FL);
|
||||
io_NormalWS = normalize(FL + i_ViewDirectionWS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_CrestNameSpaceEnd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e48e10254d2e49b8b040871986b6605
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,66 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
#ifndef CREST_WATER_REFLECTION_H
|
||||
#define CREST_WATER_REFLECTION_H
|
||||
|
||||
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Macros.hlsl"
|
||||
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Utility.hlsl"
|
||||
|
||||
float4 _Crest_ReflectionPositionNormal[2];
|
||||
Texture2DArray _Crest_ReflectionTexture;
|
||||
SamplerState sampler_Crest_ReflectionTexture;
|
||||
|
||||
m_CrestNameSpace
|
||||
|
||||
half4 PlanarReflection
|
||||
(
|
||||
const Texture2DArray i_ReflectionsTexture,
|
||||
const SamplerState i_ReflectionsSampler,
|
||||
const half i_Intensity,
|
||||
const half i_Smoothness,
|
||||
const half i_Roughness,
|
||||
const half3 i_NormalWS,
|
||||
const half i_NormalStrength,
|
||||
const half3 i_ViewDirectionWS,
|
||||
const float2 i_PositionNDC,
|
||||
const bool i_Underwater
|
||||
)
|
||||
{
|
||||
half3 planeNormal = half3(0.0, i_Underwater ? -1.0 : 1.0, 0.0);
|
||||
half3 reflected = reflect(-i_ViewDirectionWS, lerp(planeNormal, i_NormalWS, i_NormalStrength));
|
||||
reflected.y = -reflected.y;
|
||||
|
||||
float4 positionCS = mul(UNITY_MATRIX_VP, half4(reflected, 0.0));
|
||||
#if UNITY_UV_STARTS_AT_TOP
|
||||
positionCS.y = -positionCS.y;
|
||||
#endif
|
||||
|
||||
float2 positionNDC = positionCS.xy * rcp(positionCS.w) * 0.5 + 0.5;
|
||||
|
||||
// Cancel out distortion if out of bounds. We could make this nicer by doing an edge fade but the improvement is
|
||||
// barely noticeable. Edge fade requires recalculating the above a second time.
|
||||
{
|
||||
float4 positionAndNormal = _Crest_ReflectionPositionNormal[i_Underwater];
|
||||
if (dot(positionNDC - positionAndNormal.xy, positionAndNormal.zw) < 0.0)
|
||||
{
|
||||
positionNDC = lerp(i_PositionNDC, positionNDC, 0.25);
|
||||
}
|
||||
}
|
||||
|
||||
const half roughness = PerceptualSmoothnessToPerceptualRoughness(i_Smoothness);
|
||||
const half level = PerceptualRoughnessToMipmapLevel(roughness, i_Roughness);
|
||||
half4 reflection = i_ReflectionsTexture.SampleLevel(sampler_Crest_ReflectionTexture, float3(positionNDC, i_Underwater), level);
|
||||
|
||||
// If more than four layers are used on the terrain, they will appear black if HDR
|
||||
// is enabled on the planar reflection camera. Alpha is probably a negative value.
|
||||
reflection.a = saturate(reflection.a);
|
||||
|
||||
reflection.a *= i_Intensity;
|
||||
|
||||
return reflection;
|
||||
}
|
||||
|
||||
m_CrestNameSpaceEnd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 59ed70386a75c40a594ac82af7bd817b
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,113 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
#ifndef CREST_WATER_REFRACTION_H
|
||||
#define CREST_WATER_REFRACTION_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/Utility/Depth.hlsl"
|
||||
|
||||
#if (CREST_PORTALS != 0)
|
||||
#include "Packages/com.waveharmonic.crest.portals/Runtime/Shaders/Library/Portals.hlsl"
|
||||
#endif
|
||||
|
||||
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Utility.hlsl"
|
||||
|
||||
#ifndef SUPPORTS_FOVEATED_RENDERING_NON_UNIFORM_RASTER
|
||||
#define FoveatedRemapLinearToNonUniform(uv) uv
|
||||
#endif
|
||||
|
||||
m_CrestNameSpace
|
||||
|
||||
// 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 half3 i_NormalWS,
|
||||
const float2 i_PositionNDC,
|
||||
const float i_PixelZ,
|
||||
const half3 i_SceneColorUnrefracted,
|
||||
const float i_SceneZ,
|
||||
const float i_SceneZRaw,
|
||||
const bool i_Underwater,
|
||||
out half3 o_SceneColor,
|
||||
out float o_SceneDistance,
|
||||
out float3 o_ScenePositionWS,
|
||||
out bool o_Caustics
|
||||
)
|
||||
{
|
||||
float2 positionNDC = i_PositionNDC;
|
||||
float sceneDepthRaw = i_SceneZRaw;
|
||||
|
||||
o_Caustics = true;
|
||||
|
||||
// View ray intersects geometry surface either above or below water surface.
|
||||
float2 refractOffset = i_RefractionStrength * i_NormalWS.xz;
|
||||
if (!i_Underwater)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Blend at the edge of the screen to avoid artifacts.
|
||||
refractOffset *= 1.0 - EdgeBlendingFactor(positionNDC, i_PixelZ);
|
||||
|
||||
const float2 positionNDCRefracted = FoveatedRemapLinearToNonUniform(positionNDC + refractOffset);
|
||||
float sceneDepthRawRefracted = SHADERGRAPH_SAMPLE_SCENE_DEPTH(positionNDCRefracted);
|
||||
|
||||
#if (CREST_PORTALS != 0)
|
||||
#if _ALPHATEST_ON
|
||||
// Portals
|
||||
ApplyPortalRefractions(positionNDCRefracted, i_SceneZRaw, i_Underwater, sceneDepthRawRefracted, o_Caustics);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
const float sceneZRefract = Utility::CrestLinearEyeDepth(sceneDepthRawRefracted);
|
||||
|
||||
// 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);
|
||||
|
||||
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;
|
||||
|
||||
// NOTE: Causes refraction artifact with caustics. Cannot remember exactly why this was added.
|
||||
// o_Caustics = false;
|
||||
positionNDC = FoveatedRemapLinearToNonUniform(positionNDC);
|
||||
}
|
||||
|
||||
if (i_Underwater)
|
||||
{
|
||||
// Depth fog is handled by underwater shader.
|
||||
o_SceneDistance = i_PixelZ;
|
||||
}
|
||||
|
||||
o_ScenePositionWS = ComputeWorldSpacePosition(positionNDC, sceneDepthRaw, UNITY_MATRIX_I_VP);
|
||||
#if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0)
|
||||
o_ScenePositionWS += _WorldSpaceCameraPos;
|
||||
#endif
|
||||
}
|
||||
|
||||
m_CrestNameSpaceEnd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bede8020b874c4bc389767163dc07528
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,56 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
// Constants for shader graph. For example, we can force shader features when we have yet to make a keyword for it in
|
||||
// shader graph.
|
||||
|
||||
// This file must be included before all other includes. And it must be done for every node. This is due to #ifndef
|
||||
// limiting includes from being evaluated once, and we cannot specify the order because shader graph does this.
|
||||
|
||||
#ifndef CREST_SHADERGRAPH_CONSTANTS_H
|
||||
#define CREST_SHADERGRAPH_CONSTANTS_H
|
||||
|
||||
#ifdef UNIVERSAL_PIPELINE_CORE_INCLUDED
|
||||
#define CREST_URP 1
|
||||
|
||||
#if (SHADERPASS == SHADERPASS_SHADOWCASTER)
|
||||
#define CREST_SHADOWPASS 1
|
||||
#endif
|
||||
|
||||
#if _SURFACE_TYPE_TRANSPARENT
|
||||
#define d_Transparent 1
|
||||
#endif
|
||||
|
||||
#elif BUILTIN_TARGET_API
|
||||
#define CREST_BIRP 1
|
||||
|
||||
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Utility/Legacy/InputsDriven.hlsl"
|
||||
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Utility/Legacy/Common.hlsl"
|
||||
|
||||
#if _BUILTIN_SURFACE_TYPE_TRANSPARENT
|
||||
#define d_Transparent 1
|
||||
#endif
|
||||
|
||||
// SHADERPASS is currently broken:
|
||||
// https://forum.unity.com/threads/built-in-renderer-shaderpass-include-in-wrong-place.1444156/
|
||||
// #if (SHADERPASS == SHADERPASS_SHADOWCASTER)
|
||||
// #define CREST_SHADOWPASS 1
|
||||
// #endif
|
||||
#else
|
||||
// HDRP does not appear to have a reliable keyword to target.
|
||||
#define CREST_HDRP 1
|
||||
|
||||
#if _SURFACE_TYPE_TRANSPARENT
|
||||
#define d_Transparent 1
|
||||
#endif
|
||||
|
||||
#if (SHADERPASS == SHADERPASS_SHADOWS)
|
||||
#define CREST_SHADOWPASS 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(CREST_HDRP) && (SHADERPASS == SHADERPASS_FORWARD)
|
||||
#define CREST_HDRP_FORWARD_PASS 1
|
||||
#endif
|
||||
|
||||
#endif // CREST_SHADERGRAPH_CONSTANTS_H
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a641876bd41254d07831fd1b0b92f99b
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,38 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
#ifndef CREST_UTILITY_H
|
||||
#define CREST_UTILITY_H
|
||||
|
||||
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Macros.hlsl"
|
||||
|
||||
m_CrestNameSpace
|
||||
|
||||
half InverseLerp(half a, half b, half t)
|
||||
{
|
||||
return (t - a) / (b - a);
|
||||
}
|
||||
|
||||
// Taken from:
|
||||
// https://github.com/Unity-Technologies/Graphics/blob/f56d2b265eb9e01b0376623e909f98c88bc60662/Packages/com.unity.render-pipelines.high-definition/Runtime/Surface/Shaders/WaterUtilities.hlsl#L781-L797
|
||||
float EdgeBlendingFactor(float2 screenPosition, float distanceToWaterSurface)
|
||||
{
|
||||
// Convert the screen position to NDC
|
||||
float2 screenPosNDC = screenPosition * 2 - 1;
|
||||
|
||||
// We want the value to be 0 at the center and go to 1 at the edges
|
||||
float distanceToEdge = 1.0 - min((1.0 - abs(screenPosNDC.x)), (1.0 - abs(screenPosNDC.y)));
|
||||
|
||||
// What we want here is:
|
||||
// - +inf -> 0.5 value is 0
|
||||
// - 0.5-> 0.25 value is going from 0 to 1
|
||||
// - 0.25 -> 0 value is 1
|
||||
float distAttenuation = 1.0 - saturate((distanceToWaterSurface - 0.75) / 0.25);
|
||||
|
||||
// Based on if the water surface is close, we want to make the blending region even bigger
|
||||
return lerp(saturate((distanceToEdge - 0.8) / (0.2)), saturate(distanceToEdge + 0.25), distAttenuation);
|
||||
}
|
||||
|
||||
m_CrestNameSpaceEnd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8a725a22984064d758e158a964ac1255
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,186 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
// Guard against missing uniforms.
|
||||
#ifdef SHADERPASS
|
||||
|
||||
#define m_Properties \
|
||||
const float3 i_PositionWS, \
|
||||
const float3 i_ObjectPosition, \
|
||||
const float3 i_CameraPosition, \
|
||||
const float i_Time, \
|
||||
out float3 o_PositionWS, \
|
||||
out float2 o_UndisplacedXZ, \
|
||||
out float o_LodAlpha, \
|
||||
out half o_WaterLevelOffset, \
|
||||
out float2 o_WaterLevelDerivatives, \
|
||||
out half2 o_Flow
|
||||
|
||||
// Guard against Shader Graph preview.
|
||||
#ifndef SHADERGRAPH_PREVIEW
|
||||
|
||||
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Surface/Shim.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/InputsDriven.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_URP
|
||||
#if (SHADERPASS == SHADERPASS_MOTION_VECTORS)
|
||||
#define _TRANSPARENT_WRITES_MOTION_VEC 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if _TRANSPARENT_WRITES_MOTION_VEC
|
||||
#define m_Slice clamp(_Crest_LodIndex + (isMotionVectors ? g_Crest_LodChange : 0), 0, g_Crest_LodCount)
|
||||
#define m_Make(slice) Make(slice, isMotionVectors)
|
||||
#else
|
||||
#define m_Slice _Crest_LodIndex
|
||||
#define m_Make(slice) Make(slice)
|
||||
#endif
|
||||
|
||||
m_CrestNameSpace
|
||||
|
||||
void Vertex(m_Properties)
|
||||
{
|
||||
// This will get called twice.
|
||||
// With current and previous time respectively.
|
||||
|
||||
o_UndisplacedXZ = 0.0;
|
||||
o_LodAlpha = 0.0;
|
||||
o_WaterLevelOffset = 0.0;
|
||||
o_WaterLevelDerivatives = 0.0;
|
||||
o_Flow = 0.0;
|
||||
|
||||
const bool isMotionVectors = i_Time < _Time.y;
|
||||
|
||||
const float slice0 = m_Slice;
|
||||
const float slice1 = slice0 + 1;
|
||||
const Cascade cascade0 = Cascade::m_Make(slice0);
|
||||
const Cascade cascade1 = Cascade::m_Make(slice1);
|
||||
|
||||
o_PositionWS = i_PositionWS;
|
||||
|
||||
// Vertex snapping and LOD transition.
|
||||
SnapAndTransitionVertLayout
|
||||
(
|
||||
_Crest_ChunkMeshScaleAlpha,
|
||||
Cascade::Make(_Crest_LodIndex),
|
||||
_Crest_ChunkGeometryGridWidth,
|
||||
o_PositionWS,
|
||||
o_LodAlpha
|
||||
);
|
||||
|
||||
// Fix precision errors at edges.
|
||||
{
|
||||
// Scale up by small "epsilon" to solve numerical issues. Expand slightly about tile center.
|
||||
// :WaterGridPrecisionErrors
|
||||
const float2 tileCenterXZ = i_ObjectPosition.xz;
|
||||
const float2 cameraPositionXZ = abs(i_CameraPosition.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.
|
||||
o_PositionWS.xz = lerp(tileCenterXZ, o_PositionWS.xz, lerp(1.0, 1.01, max(cameraPositionXZ.x, cameraPositionXZ.y) * 0.00001));
|
||||
}
|
||||
|
||||
o_UndisplacedXZ = o_PositionWS.xz;
|
||||
|
||||
// Calculate sample weights. params.z allows shape to be faded out (used on last lod to support pop-less scale transitions).
|
||||
const float weight0 = (1.0 - o_LodAlpha) * cascade0._Weight;
|
||||
const float weight1 = (1.0 - weight0) * cascade1._Weight;
|
||||
|
||||
// Data that needs to be sampled at the undisplaced position.
|
||||
if (weight0 > m_CrestSampleLodThreshold)
|
||||
{
|
||||
#if _TRANSPARENT_WRITES_MOTION_VEC
|
||||
if (isMotionVectors)
|
||||
{
|
||||
Cascade::MakeAnimatedWavesSource(slice0).SampleDisplacement(o_UndisplacedXZ, weight0, o_PositionWS, o_WaterLevelDerivatives);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Cascade::MakeAnimatedWaves(slice0).SampleDisplacement(o_UndisplacedXZ, weight0, o_PositionWS, o_WaterLevelDerivatives);
|
||||
}
|
||||
}
|
||||
|
||||
if (weight1 > m_CrestSampleLodThreshold)
|
||||
{
|
||||
#if _TRANSPARENT_WRITES_MOTION_VEC
|
||||
if (isMotionVectors)
|
||||
{
|
||||
Cascade::MakeAnimatedWavesSource(slice1).SampleDisplacement(o_UndisplacedXZ, weight1, o_PositionWS, o_WaterLevelDerivatives);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Cascade::MakeAnimatedWaves(slice1).SampleDisplacement(o_UndisplacedXZ, weight1, o_PositionWS, o_WaterLevelDerivatives);
|
||||
}
|
||||
}
|
||||
|
||||
// Data that needs to be sampled at the displaced position.
|
||||
if (weight0 > m_CrestSampleLodThreshold)
|
||||
{
|
||||
#if CREST_FLOW_ON
|
||||
Cascade::MakeFlow(slice0).SampleFlow(o_UndisplacedXZ, weight0, o_Flow);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (weight1 > m_CrestSampleLodThreshold)
|
||||
{
|
||||
#if CREST_FLOW_ON
|
||||
Cascade::MakeFlow(slice1).SampleFlow(o_UndisplacedXZ, weight1, o_Flow);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if _TRANSPARENT_WRITES_MOTION_VEC
|
||||
if (isMotionVectors)
|
||||
{
|
||||
o_PositionWS.xz -= g_Crest_WaterCenter.xz;
|
||||
o_PositionWS.xz *= g_Crest_WaterScaleChange;
|
||||
o_PositionWS.xz += g_Crest_WaterCenter.xz;
|
||||
o_PositionWS += g_Crest_WaterCenterDelta;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
m_CrestNameSpaceEnd
|
||||
|
||||
#endif // SHADERGRAPH_PREVIEW
|
||||
|
||||
void Vertex_float(m_Properties)
|
||||
{
|
||||
#if SHADERGRAPH_PREVIEW
|
||||
o_PositionWS = 0.0;
|
||||
o_UndisplacedXZ = 0.0;
|
||||
o_LodAlpha = 0.0;
|
||||
o_WaterLevelOffset = 0.0;
|
||||
o_WaterLevelDerivatives = 0.0;
|
||||
o_Flow = 0.0;
|
||||
#else // SHADERGRAPH_PREVIEW
|
||||
m_Crest::Vertex
|
||||
(
|
||||
i_PositionWS,
|
||||
i_ObjectPosition,
|
||||
i_CameraPosition,
|
||||
i_Time,
|
||||
o_PositionWS,
|
||||
o_UndisplacedXZ,
|
||||
o_LodAlpha,
|
||||
o_WaterLevelOffset,
|
||||
o_WaterLevelDerivatives,
|
||||
o_Flow
|
||||
);
|
||||
#endif // SHADERGRAPH_PREVIEW
|
||||
}
|
||||
|
||||
#undef m_Properties
|
||||
|
||||
#endif // SHADERPASS
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2c406004ec98d40d292b359364c27961
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,84 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
#ifndef CREST_WATER_VOLUME_LIGHTING_H
|
||||
#define CREST_WATER_VOLUME_LIGHTING_H
|
||||
|
||||
#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/Surface/Utility.hlsl"
|
||||
|
||||
m_CrestNameSpace
|
||||
|
||||
// Schlick phase function.
|
||||
float SchlickPhase(float phaseG, float cosTheta)
|
||||
{
|
||||
const float schlickK = 1.5 * phaseG - 0.5 * phaseG * phaseG * phaseG;
|
||||
const float phaseFactor = 1.0 + schlickK * cosTheta;
|
||||
return (1.0 - schlickK * schlickK) / (4.0 * PI * phaseFactor * phaseFactor);
|
||||
}
|
||||
|
||||
void VolumeLighting
|
||||
(
|
||||
const half3 i_Absorption,
|
||||
const half3 i_Scattering,
|
||||
const half i_PhaseG,
|
||||
const half i_DirectionalLightShadow,
|
||||
const half3 i_ViewDirectionWS,
|
||||
const half3 i_AmbientLighting,
|
||||
const half3 i_PrimaryLightDirection,
|
||||
const half3 i_PrimaryLightIntensity,
|
||||
const half3 i_AdditionalLight,
|
||||
const half i_AmbientLightingTerm,
|
||||
const half i_PrimaryLightingTerm,
|
||||
const half i_WaterRayLength,
|
||||
const half3 i_SunBoost,
|
||||
const half i_ShadowsAffectAmbientLightingFactor,
|
||||
out half3 o_VolumeLight,
|
||||
out half3 o_VolumeOpacity
|
||||
)
|
||||
{
|
||||
// Extinction is light absorbed plus light scattered out.
|
||||
const half3 extinction = i_Absorption + i_Scattering;
|
||||
|
||||
const float ambientLightShadow = lerp
|
||||
(
|
||||
1.0,
|
||||
i_DirectionalLightShadow,
|
||||
saturate(min(min(extinction.x, extinction.y), extinction.z) * i_ShadowsAffectAmbientLightingFactor * g_Crest_DynamicSoftShadowsFactor)
|
||||
);
|
||||
|
||||
// Sun
|
||||
const float sunPhase = SchlickPhase(i_PhaseG, dot(i_PrimaryLightDirection, i_ViewDirectionWS));
|
||||
const float3 inScatteredSun = (1.0 + i_SunBoost) * sunPhase * i_PrimaryLightIntensity * i_PrimaryLightingTerm;
|
||||
const float3 inScatteredAmbient = i_AmbientLighting * i_AmbientLightingTerm * ambientLightShadow;
|
||||
|
||||
// Total inscattered
|
||||
const float3 inscattered = (inScatteredAmbient + i_AdditionalLight + inScatteredSun * i_DirectionalLightShadow);
|
||||
const float3 scatteringAmount = saturate(i_Scattering / max(extinction, 0.00001));
|
||||
o_VolumeLight = inscattered * scatteringAmount;
|
||||
|
||||
// Like 'alpha' value or obscurance. Volume light needs multiplying by this value to be correct in shallows.
|
||||
o_VolumeOpacity = 1.0 - exp(-extinction * max(0.0, i_WaterRayLength));
|
||||
}
|
||||
|
||||
half PinchSSS
|
||||
(
|
||||
const half i_Pinch,
|
||||
const half i_Minimum,
|
||||
const half i_Maximum,
|
||||
const half i_Falloff,
|
||||
const half i_Intensity,
|
||||
const half3 i_SunDirection,
|
||||
const half i_SunDirectionFalloff,
|
||||
const half3 i_ViewDirectionWS
|
||||
)
|
||||
{
|
||||
half pinch = pow(saturate(InverseLerp(i_Minimum, i_Maximum, max(2.0 - i_Pinch, 0.0))), i_Falloff);
|
||||
half sun = pow(saturate(dot(i_ViewDirectionWS, -i_SunDirection)), i_SunDirectionFalloff);
|
||||
return pinch * sun * i_Intensity;
|
||||
}
|
||||
|
||||
m_CrestNameSpaceEnd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bf1d64d62eeee4f058f304a0c2f36590
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 00ffe7d0b7161420897069dc6e12822c
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 625f186215c104763be7675aa2d941aa, type: 3}
|
||||
Reference in New Issue
Block a user