You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
352 lines
9.5 KiB
352 lines
9.5 KiB
3 years ago
|
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
|
||
|
|
||
|
// SSAO Pro - Unity Asset
|
||
|
// Copyright (c) 2015 - Thomas Hourdel
|
||
|
// http://www.thomashourdel.com
|
||
|
|
||
|
#ifndef SSAO_PRO_INCLUDED
|
||
|
#define SSAO_PRO_INCLUDED
|
||
|
|
||
|
// --------------------------------------------------------------------------------
|
||
|
// Uniforms
|
||
|
|
||
|
sampler2D _MainTex;
|
||
|
half4 _MainTex_TexelSize;
|
||
|
sampler2D _SSAOTex;
|
||
|
|
||
|
sampler2D_float _DepthNormalMapF32; // High precision depth map (Unity 4 only)
|
||
|
sampler2D_float _CameraDepthTexture;
|
||
|
sampler2D_float _CameraDepthNormalsTexture;
|
||
|
|
||
|
half4x4 _InverseViewProject;
|
||
|
half4x4 _CameraModelView;
|
||
|
|
||
|
sampler2D _NoiseTex;
|
||
|
half4 _Params1; // Noise Size / Sample Radius / Intensity / Distance
|
||
|
half4 _Params2; // Bias / Luminosity Contribution / Distance Cutoff / Cutoff Falloff
|
||
|
half4 _OcclusionColor;
|
||
|
|
||
|
half2 _Direction;
|
||
|
half _BilateralThreshold;
|
||
|
|
||
|
|
||
|
// --------------------------------------------------------------------------------
|
||
|
// Functions
|
||
|
|
||
|
inline half invlerp(half from, half to, half value)
|
||
|
{
|
||
|
return (value - from) / (to - from);
|
||
|
}
|
||
|
|
||
|
inline half getDepth(half2 uv)
|
||
|
{
|
||
|
#if HIGH_PRECISION_DEPTHMAP_OFF
|
||
|
return tex2D(_CameraDepthTexture, uv).x;
|
||
|
#elif HIGH_PRECISION_DEPTHMAP_ON
|
||
|
return tex2D(_DepthNormalMapF32, uv).x;
|
||
|
#endif
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
inline half3 getWSPosition(half2 uv, half depth)
|
||
|
{
|
||
|
// Compute world space position from the view depth
|
||
|
half4 pos = half4(uv.xy * 2.0 - 1.0, depth, 1.0);
|
||
|
half4 ray = mul(_InverseViewProject, pos);
|
||
|
return ray.xyz / ray.w;
|
||
|
}
|
||
|
|
||
|
inline half3 getWSNormal(half2 uv)
|
||
|
{
|
||
|
// Get the view space normal and convert it to world space
|
||
|
half3 nn = tex2D(_CameraDepthNormalsTexture, uv).xyz * half3(3.5554, 3.5554, 0) + half3(-1.7777, -1.7777, 1.0);
|
||
|
half g = 2.0 / dot(nn.xyz, nn.xyz);
|
||
|
half3 vsnormal = half3(g * nn.xy, g - 1.0); // View space
|
||
|
half3 wsnormal = mul((half3x3)_CameraModelView, vsnormal); // World space
|
||
|
return wsnormal;
|
||
|
}
|
||
|
|
||
|
inline half calcAO(half2 tcoord, half2 uv, half3 p, half3 cnorm)
|
||
|
{
|
||
|
half2 t = tcoord + uv;
|
||
|
half depth = getDepth(t);
|
||
|
half3 diff = getWSPosition(t, depth) - p; // World space
|
||
|
half3 v = normalize(diff);
|
||
|
half d = length(diff) * _Params1.w;
|
||
|
return max(0.0, dot(cnorm, v) - _Params2.x) * (1.0 / (1.0 + d)) * _Params1.z;
|
||
|
}
|
||
|
|
||
|
half ssao(half2 uv)
|
||
|
{
|
||
|
const half2 CROSS[4] = { half2(1.0, 0.0), half2(-1.0, 0.0), half2(0.0, 1.0), half2(0.0, -1.0) };
|
||
|
|
||
|
half depth = getDepth(uv);
|
||
|
half eyeDepth = LinearEyeDepth(depth);
|
||
|
|
||
|
half3 position = getWSPosition(uv, depth); // World space
|
||
|
half3 normal = getWSNormal(uv); // World space
|
||
|
|
||
|
#if defined(SAMPLE_NOISE)
|
||
|
half2 random = normalize(tex2D(_NoiseTex, _ScreenParams.xy * uv / _Params1.x).rg * 2.0 - 1.0);
|
||
|
#endif
|
||
|
|
||
|
half radius = max(_Params1.y / eyeDepth, 0.005);
|
||
|
clip(_Params2.z - eyeDepth); // Skip out of range pixels
|
||
|
half ao = 0.0;
|
||
|
|
||
|
// Sampling
|
||
|
for (int j = 0; j < 4; j++)
|
||
|
{
|
||
|
half2 coord1;
|
||
|
|
||
|
#if defined(SAMPLE_NOISE)
|
||
|
coord1 = reflect(CROSS[j], random) * radius;
|
||
|
#else
|
||
|
coord1 = CROSS[j] * radius;
|
||
|
#endif
|
||
|
|
||
|
#if !SAMPLES_VERY_LOW
|
||
|
half2 coord2 = coord1 * 0.707;
|
||
|
coord2 = half2(coord2.x - coord2.y, coord2.x + coord2.y);
|
||
|
#endif
|
||
|
|
||
|
#if SAMPLES_ULTRA // 20
|
||
|
ao += calcAO(uv, coord1 * 0.20, position, normal);
|
||
|
ao += calcAO(uv, coord2 * 0.40, position, normal);
|
||
|
ao += calcAO(uv, coord1 * 0.60, position, normal);
|
||
|
ao += calcAO(uv, coord2 * 0.80, position, normal);
|
||
|
ao += calcAO(uv, coord1, position, normal);
|
||
|
#elif SAMPLES_HIGH // 16
|
||
|
ao += calcAO(uv, coord1 * 0.25, position, normal);
|
||
|
ao += calcAO(uv, coord2 * 0.50, position, normal);
|
||
|
ao += calcAO(uv, coord1 * 0.75, position, normal);
|
||
|
ao += calcAO(uv, coord2, position, normal);
|
||
|
#elif SAMPLES_MEDIUM // 12
|
||
|
ao += calcAO(uv, coord1 * 0.30, position, normal);
|
||
|
ao += calcAO(uv, coord2 * 0.60, position, normal);
|
||
|
ao += calcAO(uv, coord1 * 0.90, position, normal);
|
||
|
#elif SAMPLES_LOW // 8
|
||
|
ao += calcAO(uv, coord1 * 0.30, position, normal);
|
||
|
ao += calcAO(uv, coord2 * 0.80, position, normal);
|
||
|
#elif SAMPLES_VERY_LOW // 4
|
||
|
ao += calcAO(uv, coord1 * 0.50, position, normal);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#if SAMPLES_ULTRA
|
||
|
ao /= 20.0;
|
||
|
#elif SAMPLES_HIGH
|
||
|
ao /= 16.0;
|
||
|
#elif SAMPLES_MEDIUM
|
||
|
ao /= 12.0;
|
||
|
#elif SAMPLES_LOW
|
||
|
ao /= 8.0;
|
||
|
#elif SAMPLES_VERY_LOW
|
||
|
ao /= 4.0;
|
||
|
#endif
|
||
|
|
||
|
// Distance cutoff
|
||
|
ao = lerp(1.0 - ao, 1.0, saturate(invlerp(_Params2.z - _Params2.w, _Params2.z, eyeDepth)));
|
||
|
|
||
|
return ao;
|
||
|
}
|
||
|
|
||
|
|
||
|
// --------------------------------------------------------------------------------
|
||
|
// SSAO
|
||
|
|
||
|
struct v_data_simple
|
||
|
{
|
||
|
float4 pos : SV_POSITION;
|
||
|
float2 uv : TEXCOORD0;
|
||
|
|
||
|
#if UNITY_UV_STARTS_AT_TOP
|
||
|
float2 uv2 : TEXCOORD1;
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
v_data_simple vert_ssao(appdata_img v)
|
||
|
{
|
||
|
v_data_simple o;
|
||
|
o.pos = UnityObjectToClipPos(v.vertex);
|
||
|
o.uv = v.texcoord;
|
||
|
|
||
|
#if UNITY_UV_STARTS_AT_TOP
|
||
|
o.uv2 = v.texcoord;
|
||
|
if (_MainTex_TexelSize.y < 0.0)
|
||
|
o.uv.y = 1.0 - o.uv.y;
|
||
|
#endif
|
||
|
|
||
|
return o;
|
||
|
}
|
||
|
|
||
|
half4 getAOColor(half ao, half2 uv)
|
||
|
{
|
||
|
#if defined(LIGHTING_CONTRIBUTION)
|
||
|
|
||
|
// Luminance for the current pixel, used to reduce the AO amount in bright areas
|
||
|
// Could potentially be replaced by the lighting pass in Deferred...
|
||
|
half3 color = tex2D(_MainTex, uv).rgb;
|
||
|
half luminance = dot(color, half3(0.299, 0.587, 0.114));
|
||
|
half aofinal = lerp(ao, 1.0, luminance * _Params2.y);
|
||
|
return half4(aofinal, aofinal, aofinal, 1.0);
|
||
|
|
||
|
#else
|
||
|
|
||
|
return half4(ao, ao, ao, 1.0);
|
||
|
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
half4 frag_ssao(v_data_simple i) : SV_Target
|
||
|
{
|
||
|
#if UNITY_UV_STARTS_AT_TOP
|
||
|
return saturate(getAOColor(ssao(i.uv), i.uv2) + _OcclusionColor);
|
||
|
#else
|
||
|
return saturate(getAOColor(ssao(i.uv), i.uv) + _OcclusionColor);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
// --------------------------------------------------------------------------------
|
||
|
// Gaussian Blur
|
||
|
|
||
|
struct v_data_blur
|
||
|
{
|
||
|
float4 pos : SV_POSITION;
|
||
|
float2 uv : TEXCOORD0;
|
||
|
float4 uv1 : TEXCOORD1;
|
||
|
float4 uv2 : TEXCOORD2;
|
||
|
};
|
||
|
|
||
|
v_data_blur vert_gaussian(appdata_img v)
|
||
|
{
|
||
|
v_data_blur o;
|
||
|
o.pos = UnityObjectToClipPos(v.vertex);
|
||
|
o.uv = MultiplyUV(UNITY_MATRIX_TEXTURE0, v.texcoord);
|
||
|
float2 d1 = 1.3846153846 * _Direction;
|
||
|
float2 d2 = 3.2307692308 * _Direction;
|
||
|
o.uv1 = float4(o.uv + d1, o.uv - d1);
|
||
|
o.uv2 = float4(o.uv + d2, o.uv - d2);
|
||
|
return o;
|
||
|
}
|
||
|
|
||
|
float4 frag_gaussian(v_data_blur i) : SV_Target
|
||
|
{
|
||
|
half3 c = tex2D(_MainTex, i.uv).rgb * 0.2270270270;
|
||
|
c += tex2D(_MainTex, i.uv1.xy).rgb * 0.3162162162;
|
||
|
c += tex2D(_MainTex, i.uv1.zw).rgb * 0.3162162162;
|
||
|
c += tex2D(_MainTex, i.uv2.xy).rgb * 0.0702702703;
|
||
|
c += tex2D(_MainTex, i.uv2.zw).rgb * 0.0702702703;
|
||
|
return half4(c, 1.0);
|
||
|
}
|
||
|
|
||
|
|
||
|
// --------------------------------------------------------------------------------
|
||
|
// Bilateral Blur
|
||
|
|
||
|
v_data_blur vert_bilateral(appdata_img v)
|
||
|
{
|
||
|
v_data_blur o;
|
||
|
o.pos = UnityObjectToClipPos(v.vertex);
|
||
|
o.uv = MultiplyUV(UNITY_MATRIX_TEXTURE0, v.texcoord);
|
||
|
float2 d2 = 2.0 * _Direction;
|
||
|
o.uv1 = float4(o.uv + _Direction, o.uv - _Direction);
|
||
|
o.uv2 = float4(o.uv + d2, o.uv - d2);
|
||
|
return o;
|
||
|
}
|
||
|
|
||
|
float4 frag_bilateral(v_data_blur i) : SV_Target
|
||
|
{
|
||
|
half4 depthTmp, coeff;
|
||
|
half depth = Linear01Depth(getDepth(i.uv));
|
||
|
half3 c = tex2D(_MainTex, i.uv).rgb;
|
||
|
|
||
|
depthTmp.x = Linear01Depth(getDepth(i.uv1.xy));
|
||
|
depthTmp.y = Linear01Depth(getDepth(i.uv1.zw));
|
||
|
depthTmp.z = Linear01Depth(getDepth(i.uv2.xy));
|
||
|
depthTmp.w = Linear01Depth(getDepth(i.uv2.zw));
|
||
|
coeff = 1.0 / (1e-06 + abs(depth - depthTmp));
|
||
|
c += tex2D(_MainTex, i.uv1.xy).rgb * coeff.x;
|
||
|
c += tex2D(_MainTex, i.uv1.zw).rgb * coeff.y;
|
||
|
c += tex2D(_MainTex, i.uv2.xy).rgb * coeff.z;
|
||
|
c += tex2D(_MainTex, i.uv2.zw).rgb * coeff.w;
|
||
|
|
||
|
c /= (coeff.x + coeff.y + coeff.z + coeff.w);
|
||
|
return half4(c, 1.0);
|
||
|
}
|
||
|
|
||
|
|
||
|
// --------------------------------------------------------------------------------
|
||
|
// High Quality Bilateral Blur
|
||
|
|
||
|
v_data_blur vert_hqbilateral(appdata_img v)
|
||
|
{
|
||
|
v_data_blur o;
|
||
|
o.pos = UnityObjectToClipPos(v.vertex);
|
||
|
o.uv = MultiplyUV(UNITY_MATRIX_TEXTURE0, v.texcoord);
|
||
|
float2 d1 = 1.3846153846 * _Direction;
|
||
|
float2 d2 = 3.2307692308 * _Direction;
|
||
|
o.uv1 = float4(o.uv + d1, o.uv - d1);
|
||
|
o.uv2 = float4(o.uv + d2, o.uv - d2);
|
||
|
return o;
|
||
|
}
|
||
|
|
||
|
float4 frag_hqbilateral(v_data_blur i) : SV_Target
|
||
|
{
|
||
|
const half2 uvs[4] = { i.uv1.xy, i.uv1.zw, i.uv2.xy, i.uv2.zw };
|
||
|
|
||
|
half depth = Linear01Depth(getDepth(i.uv));
|
||
|
half3 accum = tex2D(_MainTex, i.uv).rgb * 0.2270270270;
|
||
|
half accumWeight = 0.2270270270;
|
||
|
|
||
|
half4 depthTmp;
|
||
|
depthTmp.x = Linear01Depth(getDepth(uvs[0]));
|
||
|
depthTmp.y = Linear01Depth(getDepth(uvs[1]));
|
||
|
depthTmp.z = Linear01Depth(getDepth(uvs[2]));
|
||
|
depthTmp.w = Linear01Depth(getDepth(uvs[3]));
|
||
|
half4 diff = abs(depth - depthTmp);
|
||
|
half4 weight = (1.0 - step(_BilateralThreshold, diff)) * half4(0.3162162162, 0.3162162162, 0.0702702703, 0.0702702703);
|
||
|
|
||
|
for (int i = 0; i < 4; i++)
|
||
|
{
|
||
|
accum += weight[i] * tex2D(_MainTex, uvs[i]).rgb;
|
||
|
accumWeight += weight[i];
|
||
|
}
|
||
|
|
||
|
return half4(accum / accumWeight, 1.0);
|
||
|
}
|
||
|
|
||
|
|
||
|
// --------------------------------------------------------------------------------
|
||
|
// Composite
|
||
|
|
||
|
v_data_simple vert_composite(appdata_img v)
|
||
|
{
|
||
|
v_data_simple o;
|
||
|
o.pos = UnityObjectToClipPos(v.vertex);
|
||
|
o.uv = v.texcoord;
|
||
|
|
||
|
#if UNITY_UV_STARTS_AT_TOP
|
||
|
o.uv2 = v.texcoord;
|
||
|
if (_MainTex_TexelSize.y < 0.0)
|
||
|
o.uv.y = 1.0 - o.uv.y;
|
||
|
#endif
|
||
|
|
||
|
return o;
|
||
|
}
|
||
|
|
||
|
half4 frag_composite(v_data_simple i) : SV_Target
|
||
|
{
|
||
|
#if UNITY_UV_STARTS_AT_TOP
|
||
|
half4 color = tex2D(_MainTex, i.uv2).rgba;
|
||
|
#else
|
||
|
half4 color = tex2D(_MainTex, i.uv).rgba;
|
||
|
#endif
|
||
|
|
||
|
return half4(color.rgb * tex2D(_SSAOTex, i.uv).rgb, color.a);
|
||
|
}
|
||
|
|
||
|
#endif // SSAO_PRO_INCLUDED
|