OldBlueWater/BlueWater/Assets/Screen Space Cavity Curvature/Shaders/Shared.cginc

333 lines
11 KiB
HLSL
Raw Normal View History

2023-12-11 07:00:09 +00:00
#if HLSL
#define SAMPLE(texture, sampler, uv) SAMPLE_TEXTURE2D_X(texture, sampler, uv)
#else
#define SAMPLE(texture, sampler, uv) UNITY_SAMPLE_SCREENSPACE_TEXTURE(texture, uv)
#endif
2023-09-24 04:38:25 +00:00
//CAVITY V
#ifdef CAVITY_SAMPLES_6
#define CAVITY_SAMPLES 6
#endif
#ifdef CAVITY_SAMPLES_8
#define CAVITY_SAMPLES 8
#endif
#ifdef CAVITY_SAMPLES_12
#define CAVITY_SAMPLES 12
#endif
2023-12-11 07:00:09 +00:00
#ifdef CAVITY_SAMPLES_20
#define CAVITY_SAMPLES 20
#endif
2023-09-24 04:38:25 +00:00
#ifdef SSCC_HDRP
#define ACTUAL_CAVITY_SAMPLES (CAVITY_SAMPLES+2)
#else
#define ACTUAL_CAVITY_SAMPLES (CAVITY_SAMPLES)
#endif
float _InterleavedGradientNoise(float2 pixCoord, int frameCount)
{
const float3 magic = float3(0.06711056f, 0.00583715f, 52.9829189f);
float2 frameMagicScale = float2(2.083f, 4.867f);
pixCoord += frameCount * frameMagicScale;
return frac(magic.z * frac(dot(pixCoord, magic.xy)));
}
float3 PickSamplePoint(float2 uv, float randAddon, int index)
{
2023-12-11 07:00:09 +00:00
float2 positionSS = uv * _CavityTex_TexelSize.zw;
2023-09-24 04:38:25 +00:00
float gn = _InterleavedGradientNoise(positionSS, index);
float u = frac(gn) * 2.0 - 1.0;
float theta = gn * 6.28318530717958647693;
float sn, cs;
sincos(theta, sn, cs);
return float3(float2(cs, sn) * sqrt(1.0 - u * u), u);
}
float3x3 GetCoordinateConversionParameters(out float2 p11_22, out float2 p13_31)
{
float3x3 camProj = (float3x3)unity_CameraProjection;
//float3x3 camProj = (float3x3)/*UNITY_MATRIX_P*/_Projection;
p11_22 = rcp(float2(camProj._11, camProj._22));
p13_31 = float2(camProj._13, camProj._23);
return camProj;
}
float3 ReconstructViewPos(float2 uv, float depth, float2 p11_22, float2 p13_31)
{
#if ORTHOGRAPHIC_PROJECTION
float3 viewPos = float3(((uv.xy * 2.0 - 1.0 - p13_31) * p11_22), depth);
#else
float3 viewPos = float3(depth * ((uv.xy * 2.0 - 1.0 - p13_31) * p11_22), depth);
#endif
return viewPos;
}
void SampleDepthAndViewpos(float2 uv, float2 p11_22, float2 p13_31, out float depth, out float3 vpos)
{
depth = LinearizeDepth(FetchRawDepth(uv));
vpos = ReconstructViewPos(uv, depth, p11_22, p13_31);
}
void Cavity(float2 uv, float3 normal, out float cavity, out float edges)
{
cavity = edges = 0.0;
float2 p11_22, p13_31;
float3x3 camProj = GetCoordinateConversionParameters(p11_22, p13_31);
float depth;
float3 vpos;
SampleDepthAndViewpos(uv, p11_22, p13_31, depth, vpos);
float randAddon = uv.x * 1e-10;
float rcpSampleCount = rcp(ACTUAL_CAVITY_SAMPLES);
//UNITY_LOOP
UNITY_UNROLL
for (int i = 0; i < int(ACTUAL_CAVITY_SAMPLES); i++)
{
#if defined(SHADER_API_D3D11)
i = floor(1.0001 * i);
#endif
#if 0
float3 v_s1 = PickSamplePoint(uv.yx, randAddon, i);
#else
float3 v_s1 = PickSamplePoint(uv, randAddon, i);
#endif
v_s1 *= sqrt((i + 1.0) * rcpSampleCount) * _CavityWorldRadius * 0.5;
float3 vpos_s1 = vpos + v_s1;
float3 spos_s1 = mul(camProj, vpos_s1);
#if ORTHOGRAPHIC_PROJECTION
float2 uv_s1_01 = clamp((spos_s1.xy + 1.0) * 0.5, 0.0, 1.0);
#else
float2 uv_s1_01 = clamp((spos_s1.xy * rcp(vpos_s1.z) + 1.0) * 0.5, 0.0, 1.0);
#endif
float depth_s1 = LinearizeDepth(FetchRawDepth(uv_s1_01));
float3 vpos_s2 = ReconstructViewPos(uv_s1_01, depth_s1, p11_22, p13_31);
float3 dir = vpos_s2 - vpos;
float len = length(dir);
float f_dot = dot(dir, normal);
//float kBeta = 0.002;
float kBeta = 0.002 * 4;
float f_cavities = f_dot - kBeta * depth;
float f_edge = -f_dot - kBeta * depth;
float f_bias = 0.05 * len + 0.0001;
if (f_cavities > -f_bias)
{
float attenuation = 1.0 / (len * (1.0 + len * len * 3.));
cavity += f_cavities * attenuation;
}
if (f_edge > f_bias)
{
float attenuation = 1.0 / (len * (1.0 + len * len * 0.01));
edges += f_edge * attenuation;
}
}
//cavity *= 1.0 / ACTUAL_CAVITY_SAMPLES;
//edges *= 1.0 / ACTUAL_CAVITY_SAMPLES;
cavity *= 1.0 * _CavityWorldRadius * 0.5;
edges *= 1.0 * _CavityWorldRadius * 0.5;
float kContrast = 0.6;
cavity = pow(abs(cavity * rcpSampleCount), kContrast);
edges = pow(abs(edges * rcpSampleCount), kContrast);
cavity = clamp(cavity * _CavityDarks, 0.0, 1.0);
edges = edges * _CavityBrights;
}
//CAVITY ^
//CURVATURE V
float CurvatureSoftClamp(float curvature, float control)
{
if (curvature < 0.5 / control)
return curvature * (1.0 - curvature * control);
return 0.25 / control;
}
float Curvature(float2 uv, float3 P)
{
float3 offset = float3(_Input_TexelSize.xy, 0.0) * (_CurvaturePixelRadius);
float normal_up = FetchViewNormals(P, uv + offset.zy).g;
float normal_down = FetchViewNormals(P, uv - offset.zy).g;
float normal_right = FetchViewNormals(P, uv + offset.xz).r;
float normal_left = FetchViewNormals(P, uv - offset.xz).r;
float normal_diff = (normal_up - normal_down) + (normal_right - normal_left);
2023-12-11 07:00:09 +00:00
//if (abs(normal_diff) <= 0.1) return 0; //slight low pass filter to remove noise from camera normals precision
//new and improved low pass filter:
//if (uv.x < 0.5)
{
if (normal_diff > 0.0) normal_diff = sign(normal_diff) * pow(normal_diff, 2.0);
_CavityBrights += 0.5;
}
2023-09-24 04:38:25 +00:00
if (normal_diff >= 0.0)
return 2.0 * CurvatureSoftClamp(normal_diff, _CurvatureBrights);
else
return -2.0 * CurvatureSoftClamp(-normal_diff, _CurvatureDarks);
}
//CURVATURE ^
float invLerp(float from, float to, float value) {
return (value - from) / (to - from);
}
float remap(float origFrom, float origTo, float targetFrom, float targetTo, float value) {
float rel = invLerp(origFrom, origTo, value);
return lerp(targetFrom, targetTo, rel);
}
2023-12-11 07:00:09 +00:00
float4 Cavity_Frag(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
#ifdef UnityStereoTransformScreenSpaceTex
float2 uv = UnityStereoTransformScreenSpaceTex(input.uv);
#else
float2 uv = input.uv;
#endif
float3 P = FetchViewPos(uv);
float3 N = FetchViewNormals(P, uv);
float cavity = 0.0, edges = 0.0;
Cavity(uv, N, cavity, edges);
return float4(cavity, edges, FetchRawDepth(uv), 1.0);
}
float2 GaussianBlur(float2 uv, float2 pixelOffset)
{
const float gWeights[2] =
{
0.44908,
0.05092
};
const float gOffsets[2] =
{
0.53805,
2.06278
};
float2 colOut = 0.0;
UNITY_UNROLL
for(int i = 0; i < 2; i++)
{
float2 texCoordOffset = pixelOffset * gOffsets[i];
float2 p1 = SAMPLE(_MainTex, sampler_LinearClamp, uv + texCoordOffset).xy;
float2 p2 = SAMPLE(_MainTex, sampler_LinearClamp, uv - texCoordOffset).xy;
colOut += gWeights[i] * (p1 + p2);
}
return colOut;
}
float4 HorizontalBlur_Frag(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
return float4
(
GaussianBlur(input.uv, float2(_CavityTex_TexelSize.x, 0.0)),
SAMPLE(_MainTex, sampler_LinearClamp, input.uv).z,
1.0
);
}
float4 VerticalBlur_Frag(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
return float4
(
GaussianBlur(input.uv, float2(0.0, _CavityTex_TexelSize.y)),
SAMPLE(_MainTex, sampler_LinearClamp, input.uv).z,
1.0
);
}
2023-09-24 04:38:25 +00:00
float4 Composite_Frag(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
#ifdef UnityStereoTransformScreenSpaceTex
float2 uv = UnityStereoTransformScreenSpaceTex(input.uv);
#else
float2 uv = input.uv;
#endif
2023-12-11 07:00:09 +00:00
2023-09-24 04:38:25 +00:00
float3 P = FetchViewPos(uv);
float3 N = FetchViewNormals(P, uv);
float4 col = FetchSceneColor(uv);
float4 untouchedCol = FetchSceneColor(uv);
//float depth01 = FetchRawDepth(uv);
//if (depth01 == 1.0 || depth01 == 0.0) return col;
float curvature = 0.0;
curvature = Curvature(uv, P);
2023-12-11 07:00:09 +00:00
//float cavity = 0.0, edges = 0.0;
//Cavity(uv, N, cavity, edges);
float2 cavityTex;
#if UPSCALE_CAVITY
float2 LowResTexelSize = _CavityTex_TexelSize.xy;
float2 LowResBufferSize = _CavityTex_TexelSize.zw;
float2 Corner00UV = floor(uv * LowResBufferSize - .5f) / LowResBufferSize + .5f * LowResTexelSize;
float2 BilinearWeights = (uv - Corner00UV) * LowResBufferSize;
//xy is signal, z is depth it used
float3 TextureValues00 = SAMPLE(_CavityTex, sampler_LinearClamp, Corner00UV).xyz;
float3 TextureValues10 = SAMPLE(_CavityTex, sampler_LinearClamp, Corner00UV + float2(LowResTexelSize.x, 0)).xyz;
float3 TextureValues01 = SAMPLE(_CavityTex, sampler_LinearClamp, Corner00UV + float2(0, LowResTexelSize.y)).xyz;
float3 TextureValues11 = SAMPLE(_CavityTex, sampler_LinearClamp, Corner00UV + LowResTexelSize).xyz;
float4 CornerWeights = float4(
(1 - BilinearWeights.y) * (1 - BilinearWeights.x),
(1 - BilinearWeights.y) * BilinearWeights.x,
BilinearWeights.y * (1 - BilinearWeights.x),
BilinearWeights.y * BilinearWeights.x);
float Epsilon = .0001f/*-.0001f*//*0.0f*/;
float4 CornerDepths = abs(float4(TextureValues00.z, TextureValues10.z, TextureValues01.z, TextureValues11.z));
float SceneDepth = FetchRawDepth(uv);
float4 DepthWeights = 1.0f / (abs(CornerDepths - SceneDepth.xxxx) + Epsilon);
float4 FinalWeights = CornerWeights * DepthWeights;
cavityTex = (FinalWeights.x*TextureValues00.xy + FinalWeights.y*TextureValues10.xy + FinalWeights.z*TextureValues01.xy + FinalWeights.w*TextureValues11.xy) / dot(FinalWeights, 1);
#else
cavityTex = SAMPLE(_CavityTex, sampler_LinearClamp, uv).xy;
#endif
float cavity = cavityTex.r, edges = cavityTex.g;
2023-09-24 04:38:25 +00:00
if (uv.x < _Input_TexelSize.x * 2 || uv.y < _Input_TexelSize.y * 2 || 1 - uv.x < _Input_TexelSize.x * 2 || 1 - uv.y < _Input_TexelSize.y * 2) { curvature = cavity = edges = 0; };
col.rgb += (curvature * 0.4);
#if SATURATE_CAVITY
2023-12-11 07:00:09 +00:00
//float3 extra = col.rgb - saturate(col.rgb);
2023-09-24 04:38:25 +00:00
col.rgb = pow(saturate(col.rgb), 1 - (edges * 0.5));
col.rgb = pow(saturate(col.rgb), 1 + (cavity * 1));
2023-12-11 07:00:09 +00:00
//col.rgb += extra;
2023-09-24 04:38:25 +00:00
#else
col.rgb += (edges * 0.2);
col.rgb -= (cavity * 0.2);
#endif
//Uncomment this block of code for on/off back and forth effect preview
//if (uv.x < sin(_Time.y+(3.1415/2)) * 0.5 + 0.5)
//{
// if (uv.x > (sin(_Time.y+(3.1415/2)) * 0.5 + 0.5) - 0.002) return 0;
// return untouchedCol;
//}
#if DEBUG_EFFECT
return ((1.0 - cavity) * (1.0 + edges) * (1.0 + curvature)) * 0.25;
#elif DEBUG_NORMALS
return float4(N * 0.5 + 0.5, 1);
#endif
#if OUTPUT_TO_TEXTURE
float r = curvature * 0.4;
float g = (edges * 0.2) - (cavity * 0.2);
return float4(r * rcp(max(1, P.z * _DistanceFade)) * _EffectIntensity, g * rcp(max(1, P.z * _DistanceFade)) * _EffectIntensity, 1, 1);
//Values rescaled so they're more consistent to work with, if you just +curvature+edges it should match 'screen' output
#else
return lerp(untouchedCol, col, rcp(max(1, P.z * _DistanceFade)) * _EffectIntensity);
#endif
}