This commit is contained in:
Andras Schmelczer 2026-09-13 20:53:11 +01:00
commit 36a53f343e
58 changed files with 300431 additions and 0 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: b8d56fc3449f426408c23c723b58d7b5
timeCreated: 1460363486
licenseType: Store
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,500 @@
// Upgrade NOTE: commented out 'float4x4 _WorldToCamera', a built-in variable
// Upgrade NOTE: replaced '_WorldToCamera' with 'unity_WorldToCamera'
#ifndef __AMBIENT_OCCLUSION__
#define __AMBIENT_OCCLUSION__
#include "UnityCG.cginc"
#include "Common.cginc"
// --------
// Options for further customization
// --------
// By default, a 5-tap Gaussian with the linear sampling technique is used
// in the bilateral noise filter. It can be replaced with a 7-tap Gaussian
// with adaptive sampling by enabling the macro below. Although the
// differences are not noticeable in most cases, it may provide preferable
// results with some special usage (e.g. NPR without textureing).
// #define BLUR_HIGH_QUALITY
// By default, a fixed sampling pattern is used in the AO estimator. Although
// this gives preferable results in most cases, a completely random sampling
// pattern could give aesthetically better results. Disable the macro below
// to use such a random pattern instead of the fixed one.
#define FIX_SAMPLING_PATTERN
// The SampleNormal function normalizes samples from G-buffer because
// they're possibly unnormalized. We can eliminate this if it can be said
// that there is no wrong shader that outputs unnormalized normals.
// #define VALIDATE_NORMALS
// The constant below determines the contrast of occlusion. This allows
// users to control over/under occlusion. At the moment, this is not exposed
// to the editor because it<69>s rarely useful.
static const float kContrast = 0.6;
// The constant below controls the geometry-awareness of the bilateral
// filter. The higher value, the more sensitive it is.
static const float kGeometryCoeff = 0.8;
// The constants below are used in the AO estimator. Beta is mainly used
// for suppressing self-shadowing noise, and Epsilon is used to prevent
// calculation underflow. See the paper (Morgan 2011 http://goo.gl/2iz3P)
// for further details of these constants.
static const float kBeta = 0.002;
// --------
// System built-in variables
sampler2D _CameraGBufferTexture2;
sampler2D_float _CameraDepthTexture;
sampler2D _CameraDepthNormalsTexture;
float4 _CameraDepthTexture_ST;
// Sample count
#if !defined(SHADER_API_GLES)
int _SampleCount;
#else
// GLES2: In many cases, dynamic looping is not supported.
static const int _SampleCount = 3;
#endif
// Source texture properties
sampler2D _OcclusionTexture;
float4 _OcclusionTexture_TexelSize;
// Other parameters
half _Intensity;
float _Radius;
float _Downsample;
float3 _FogParams; // x: density, y: start, z: end
// Accessors for packed AO/normal buffer
fixed4 PackAONormal(fixed ao, fixed3 n)
{
return fixed4(ao, n * 0.5 + 0.5);
}
fixed GetPackedAO(fixed4 p)
{
return p.r;
}
fixed3 GetPackedNormal(fixed4 p)
{
return p.gba * 2.0 - 1.0;
}
// Boundary check for depth sampler
// (returns a very large value if it lies out of bounds)
float CheckBounds(float2 uv, float d)
{
float ob = any(uv < 0) + any(uv > 1);
#if defined(UNITY_REVERSED_Z)
ob += (d <= 0.00001);
#else
ob += (d >= 0.99999);
#endif
return ob * 1e8;
}
// Depth/normal sampling functions
float SampleDepth(float2 uv)
{
#if defined(SOURCE_GBUFFER) || defined(SOURCE_DEPTH)
float d = LinearizeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv));
#else
float4 cdn = tex2D(_CameraDepthNormalsTexture, uv);
float d = DecodeFloatRG(cdn.zw);
#endif
return d * _ProjectionParams.z + CheckBounds(uv, d);
}
float3 SampleNormal(float2 uv)
{
#if defined(SOURCE_GBUFFER)
float3 norm = tex2D(_CameraGBufferTexture2, uv).xyz;
norm = norm * 2 - any(norm); // gets (0,0,0) when norm == 0
norm = mul((float3x3)unity_WorldToCamera, norm);
#if defined(VALIDATE_NORMALS)
norm = normalize(norm);
#endif
return norm;
#else
float4 cdn = tex2D(_CameraDepthNormalsTexture, uv);
return DecodeViewNormalStereo(cdn) * float3(1.0, 1.0, -1.0);
#endif
}
float SampleDepthNormal(float2 uv, out float3 normal)
{
#if defined(SOURCE_GBUFFER) || defined(SOURCE_DEPTH)
normal = SampleNormal(uv);
return SampleDepth(uv);
#else
float4 cdn = tex2D(_CameraDepthNormalsTexture, uv);
normal = DecodeViewNormalStereo(cdn) * float3(1.0, 1.0, -1.0);
float d = DecodeFloatRG(cdn.zw);
return d * _ProjectionParams.z + CheckBounds(uv, d);
#endif
}
// Normal vector comparer (for geometry-aware weighting)
half CompareNormal(half3 d1, half3 d2)
{
return smoothstep(kGeometryCoeff, 1.0, dot(d1, d2));
}
// Common vertex shader
struct VaryingsMultitex
{
float4 pos : SV_POSITION;
half2 uv : TEXCOORD0; // Original UV
half2 uv01 : TEXCOORD1; // Alternative UV (supports v-flip case)
half2 uvSPR : TEXCOORD2; // Single pass stereo rendering UV
};
VaryingsMultitex VertMultitex(AttributesDefault v)
{
half2 uvAlt = v.texcoord.xy;
#if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y < 0.0) uvAlt.y = 1.0 - uvAlt.y;
#endif
VaryingsMultitex o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord.xy;
o.uv01 = uvAlt;
o.uvSPR = UnityStereoTransformScreenSpaceTex(uvAlt);
return o;
}
// Trigonometric function utility
float2 CosSin(float theta)
{
float sn, cs;
sincos(theta, sn, cs);
return float2(cs, sn);
}
// Pseudo random number generator with 2D coordinates
float UVRandom(float u, float v)
{
float f = dot(float2(12.9898, 78.233), float2(u, v));
return frac(43758.5453 * sin(f));
}
// Check if the camera is perspective.
// (returns 1.0 when orthographic)
float CheckPerspective(float x)
{
return lerp(x, 1.0, unity_OrthoParams.w);
}
// Reconstruct view-space position from UV and depth.
// p11_22 = (unity_CameraProjection._11, unity_CameraProjection._22)
// p13_31 = (unity_CameraProjection._13, unity_CameraProjection._23)
float3 ReconstructViewPos(float2 uv, float depth, float2 p11_22, float2 p13_31)
{
return float3((uv * 2.0 - 1.0 - p13_31) / p11_22 * CheckPerspective(depth), depth);
}
// Sample point picker
float3 PickSamplePoint(float2 uv, float index)
{
// Uniformaly distributed points on a unit sphere http://goo.gl/X2F1Ho
#if defined(FIX_SAMPLING_PATTERN)
float gn = GradientNoise(uv * _Downsample);
// FIXME: This was added to avoid a NVIDIA driver issue.
// vvvvvvvvvvvv
float u = frac(UVRandom(0.0, index + uv.x * 1e-10) + gn) * 2.0 - 1.0;
float theta = (UVRandom(1.0, index + uv.x * 1e-10) + gn) * UNITY_PI_2;
#else
float u = UVRandom(uv.x + _Time.x, uv.y + index) * 2.0 - 1.0;
float theta = UVRandom(-uv.x - _Time.x, uv.y + index) * UNITY_PI_2;
#endif
float3 v = float3(CosSin(theta) * sqrt(1.0 - u * u), u);
// Make them distributed between [0, _Radius]
float l = sqrt((index + 1.0) / _SampleCount) * _Radius;
return v * l;
}
// Fog handling in forward
half ComputeFog(float z)
{
half fog = 0.0;
#if FOG_LINEAR
fog = (_FogParams.z - z) / (_FogParams.z - _FogParams.y);
#elif FOG_EXP
fog = exp2(-_FogParams.x * z);
#else // FOG_EXP2
fog = _FogParams.x * z;
fog = exp2(-fog * fog);
#endif
return saturate(fog);
}
float ComputeDistance(float depth)
{
float dist = depth * _ProjectionParams.z;
dist -= _ProjectionParams.y;
return dist;
}
//
// Distance-based AO estimator based on Morgan 2011 http://goo.gl/2iz3P
//
half4 FragAO(VaryingsMultitex i) : SV_Target
{
float2 uv = i.uv;
// Parameters used in coordinate conversion
float3x3 proj = (float3x3)unity_CameraProjection;
float2 p11_22 = float2(unity_CameraProjection._11, unity_CameraProjection._22);
float2 p13_31 = float2(unity_CameraProjection._13, unity_CameraProjection._23);
// View space normal and depth
float3 norm_o;
float depth_o = SampleDepthNormal(UnityStereoScreenSpaceUVAdjust(uv, _CameraDepthTexture_ST), norm_o);
#if defined(SOURCE_DEPTHNORMALS)
// Offset the depth value to avoid precision error.
// (depth in the DepthNormals mode has only 16-bit precision)
depth_o -= _ProjectionParams.z / 65536;
#endif
// Reconstruct the view-space position.
float3 vpos_o = ReconstructViewPos(i.uv01, depth_o, p11_22, p13_31);
float ao = 0.0;
for (int s = 0; s < _SampleCount; s++)
{
// Sample point
#if defined(SHADER_API_D3D11)
// This 'floor(1.0001 * s)' operation is needed to avoid a NVidia
// shader issue. This issue is only observed on DX11.
float3 v_s1 = PickSamplePoint(uv, floor(1.0001 * s));
#else
float3 v_s1 = PickSamplePoint(uv, s);
#endif
v_s1 = faceforward(v_s1, -norm_o, v_s1);
float3 vpos_s1 = vpos_o + v_s1;
// Reproject the sample point
float3 spos_s1 = mul(proj, vpos_s1);
float2 uv_s1_01 = (spos_s1.xy / CheckPerspective(vpos_s1.z) + 1.0) * 0.5;
// Depth at the sample point
float depth_s1 = SampleDepth(UnityStereoScreenSpaceUVAdjust(uv_s1_01, _CameraDepthTexture_ST));
// Relative position of the sample point
float3 vpos_s2 = ReconstructViewPos(uv_s1_01, depth_s1, p11_22, p13_31);
float3 v_s2 = vpos_s2 - vpos_o;
// Estimate the obscurance value
float a1 = max(dot(v_s2, norm_o) - kBeta * depth_o, 0.0);
float a2 = dot(v_s2, v_s2) + EPSILON;
ao += a1 / a2;
}
ao *= _Radius; // intensity normalization
// Apply other parameters.
ao = pow(ao * _Intensity / _SampleCount, kContrast);
// Apply fog when enabled (forward-only)
#if !FOG_OFF
float d = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv));
d = ComputeDistance(d);
ao *= ComputeFog(d);
#endif
return PackAONormal(ao, norm_o);
}
// Geometry-aware separable bilateral filter
half4 FragBlur(VaryingsMultitex i) : SV_Target
{
#if defined(BLUR_HORIZONTAL)
// Horizontal pass: Always use 2 texels interval to match to
// the dither pattern.
float2 delta = float2(_MainTex_TexelSize.x * 2.0, 0.0);
#else
// Vertical pass: Apply _Downsample to match to the dither
// pattern in the original occlusion buffer.
float2 delta = float2(0.0, _MainTex_TexelSize.y / _Downsample * 2.0);
#endif
#if defined(BLUR_HIGH_QUALITY)
// High quality 7-tap Gaussian with adaptive sampling
fixed4 p0 = tex2D(_MainTex, i.uvSPR);
fixed4 p1a = tex2D(_MainTex, i.uvSPR - delta);
fixed4 p1b = tex2D(_MainTex, i.uvSPR + delta);
fixed4 p2a = tex2D(_MainTex, i.uvSPR - delta * 2.0);
fixed4 p2b = tex2D(_MainTex, i.uvSPR + delta * 2.0);
fixed4 p3a = tex2D(_MainTex, i.uvSPR - delta * 3.2307692308);
fixed4 p3b = tex2D(_MainTex, i.uvSPR + delta * 3.2307692308);
#if defined(BLUR_SAMPLE_CENTER_NORMAL)
fixed3 n0 = SampleNormal(i.uvSPR);
#else
fixed3 n0 = GetPackedNormal(p0);
#endif
half w0 = 0.37004405286;
half w1a = CompareNormal(n0, GetPackedNormal(p1a)) * 0.31718061674;
half w1b = CompareNormal(n0, GetPackedNormal(p1b)) * 0.31718061674;
half w2a = CompareNormal(n0, GetPackedNormal(p2a)) * 0.19823788546;
half w2b = CompareNormal(n0, GetPackedNormal(p2b)) * 0.19823788546;
half w3a = CompareNormal(n0, GetPackedNormal(p3a)) * 0.11453744493;
half w3b = CompareNormal(n0, GetPackedNormal(p3b)) * 0.11453744493;
half s;
s = GetPackedAO(p0) * w0;
s += GetPackedAO(p1a) * w1a;
s += GetPackedAO(p1b) * w1b;
s += GetPackedAO(p2a) * w2a;
s += GetPackedAO(p2b) * w2b;
s += GetPackedAO(p3a) * w3a;
s += GetPackedAO(p3b) * w3b;
s /= w0 + w1a + w1b + w2a + w2b + w3a + w3b;
#else
// Fater 5-tap Gaussian with linear sampling
fixed4 p0 = tex2D(_MainTex, i.uvSPR);
fixed4 p1a = tex2D(_MainTex, i.uvSPR - delta * 1.3846153846);
fixed4 p1b = tex2D(_MainTex, i.uvSPR + delta * 1.3846153846);
fixed4 p2a = tex2D(_MainTex, i.uvSPR - delta * 3.2307692308);
fixed4 p2b = tex2D(_MainTex, i.uvSPR + delta * 3.2307692308);
#if defined(BLUR_SAMPLE_CENTER_NORMAL)
fixed3 n0 = SampleNormal(i.uvSPR);
#else
fixed3 n0 = GetPackedNormal(p0);
#endif
half w0 = 0.2270270270;
half w1a = CompareNormal(n0, GetPackedNormal(p1a)) * 0.3162162162;
half w1b = CompareNormal(n0, GetPackedNormal(p1b)) * 0.3162162162;
half w2a = CompareNormal(n0, GetPackedNormal(p2a)) * 0.0702702703;
half w2b = CompareNormal(n0, GetPackedNormal(p2b)) * 0.0702702703;
half s;
s = GetPackedAO(p0) * w0;
s += GetPackedAO(p1a) * w1a;
s += GetPackedAO(p1b) * w1b;
s += GetPackedAO(p2a) * w2a;
s += GetPackedAO(p2b) * w2b;
s /= w0 + w1a + w1b + w2a + w2b;
#endif
return PackAONormal(s, n0);
}
// Gamma encoding (only needed in gamma lighting mode)
half EncodeAO(half x)
{
half x_g = 1.0 - max(1.055 * pow(1.0 - x, 0.416666667) - 0.055, 0.0);
// ColorSpaceLuminance.w == 0 (gamma) or 1 (linear)
return lerp(x_g, x, unity_ColorSpaceLuminance.w);
}
// Geometry-aware bilateral filter (single pass/small kernel)
half BlurSmall(sampler2D tex, float2 uv, float2 delta)
{
fixed4 p0 = tex2D(tex, uv);
fixed4 p1 = tex2D(tex, uv + float2(-delta.x, -delta.y));
fixed4 p2 = tex2D(tex, uv + float2(+delta.x, -delta.y));
fixed4 p3 = tex2D(tex, uv + float2(-delta.x, +delta.y));
fixed4 p4 = tex2D(tex, uv + float2(+delta.x, +delta.y));
fixed3 n0 = GetPackedNormal(p0);
half w0 = 1.0;
half w1 = CompareNormal(n0, GetPackedNormal(p1));
half w2 = CompareNormal(n0, GetPackedNormal(p2));
half w3 = CompareNormal(n0, GetPackedNormal(p3));
half w4 = CompareNormal(n0, GetPackedNormal(p4));
half s;
s = GetPackedAO(p0) * w0;
s += GetPackedAO(p1) * w1;
s += GetPackedAO(p2) * w2;
s += GetPackedAO(p3) * w3;
s += GetPackedAO(p4) * w4;
return s / (w0 + w1 + w2 + w3 + w4);
}
// Final composition shader
half4 FragComposition(VaryingsMultitex i) : SV_Target
{
float2 delta = _MainTex_TexelSize.xy / _Downsample;
half ao = BlurSmall(_OcclusionTexture, i.uvSPR, delta);
half4 color = tex2D(_MainTex, i.uvSPR);
#if !defined(DEBUG_COMPOSITION)
color.rgb *= 1.0 - EncodeAO(ao);
#else
color.rgb = 1.0 - EncodeAO(ao);
#endif
return color;
}
// Final composition shader (ambient-only mode)
VaryingsDefault VertCompositionGBuffer(AttributesDefault v)
{
VaryingsDefault o;
o.pos = v.vertex;
#if UNITY_UV_STARTS_AT_TOP
o.uv = v.texcoord.xy * float2(1.0, -1.0) + float2(0.0, 1.0);
#else
o.uv = v.texcoord.xy;
#endif
o.uvSPR = UnityStereoTransformScreenSpaceTex(o.uv);
return o;
}
#if !SHADER_API_GLES // excluding the MRT pass under GLES2
struct CompositionOutput
{
half4 gbuffer0 : SV_Target0;
half4 gbuffer3 : SV_Target1;
};
CompositionOutput FragCompositionGBuffer(VaryingsDefault i)
{
// Workaround: _OcclusionTexture_Texelsize hasn't been set properly
// for some reasons. Use _ScreenParams instead.
float2 delta = (_ScreenParams.zw - 1.0) / _Downsample;
half ao = BlurSmall(_OcclusionTexture, i.uvSPR, delta);
CompositionOutput o;
o.gbuffer0 = half4(0.0, 0.0, 0.0, ao);
o.gbuffer3 = half4((half3)EncodeAO(ao), 0.0);
return o;
}
#else
fixed4 FragCompositionGBuffer(VaryingsDefault i) : SV_Target0
{
return 0.0;
}
#endif
#endif // __AMBIENT_OCCLUSION__

View file

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 447591ee3d9d4204899be5fe25968ea0
timeCreated: 1473323470
licenseType: Store
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,119 @@
Shader "Hidden/Post FX/Ambient Occlusion"
{
CGINCLUDE
#pragma target 3.0
ENDCG
SubShader
{
ZTest Always Cull Off ZWrite Off
// 0: Occlusion estimation with CameraDepthTexture
Pass
{
CGPROGRAM
#pragma vertex VertMultitex
#pragma fragment FragAO
#pragma multi_compile FOG_OFF FOG_LINEAR FOG_EXP FOG_EXP2
#define SOURCE_DEPTH
#include "AmbientOcclusion.cginc"
ENDCG
}
// 1: Occlusion estimation with CameraDepthNormalsTexture
Pass
{
CGPROGRAM
#pragma vertex VertMultitex
#pragma fragment FragAO
#pragma multi_compile FOG_OFF FOG_LINEAR FOG_EXP FOG_EXP2
#define SOURCE_DEPTHNORMALS
#include "AmbientOcclusion.cginc"
ENDCG
}
// 2: Occlusion estimation with G-Buffer
Pass
{
CGPROGRAM
#pragma vertex VertMultitex
#pragma fragment FragAO
#pragma multi_compile FOG_OFF FOG_LINEAR FOG_EXP FOG_EXP2
#define SOURCE_GBUFFER
#include "AmbientOcclusion.cginc"
ENDCG
}
// 3: Separable blur (horizontal pass) with CameraDepthNormalsTexture
Pass
{
CGPROGRAM
#pragma vertex VertMultitex
#pragma fragment FragBlur
#define SOURCE_DEPTHNORMALS
#define BLUR_HORIZONTAL
#define BLUR_SAMPLE_CENTER_NORMAL
#include "AmbientOcclusion.cginc"
ENDCG
}
// 4: Separable blur (horizontal pass) with G-Buffer
Pass
{
CGPROGRAM
#pragma vertex VertMultitex
#pragma fragment FragBlur
#define SOURCE_GBUFFER
#define BLUR_HORIZONTAL
#define BLUR_SAMPLE_CENTER_NORMAL
#include "AmbientOcclusion.cginc"
ENDCG
}
// 5: Separable blur (vertical pass)
Pass
{
CGPROGRAM
#pragma vertex VertMultitex
#pragma fragment FragBlur
#define BLUR_VERTICAL
#include "AmbientOcclusion.cginc"
ENDCG
}
// 6: Final composition
Pass
{
CGPROGRAM
#pragma vertex VertMultitex
#pragma fragment FragComposition
#include "AmbientOcclusion.cginc"
ENDCG
}
// 7: Final composition (ambient only mode)
Pass
{
Blend Zero OneMinusSrcColor, Zero OneMinusSrcAlpha
CGPROGRAM
#pragma vertex VertCompositionGBuffer
#pragma fragment FragCompositionGBuffer
#include "AmbientOcclusion.cginc"
ENDCG
}
// 8: Debug visualization
Pass
{
CGPROGRAM
#pragma vertex VertMultitex
#pragma fragment FragComposition
#define DEBUG_COMPOSITION
#include "AmbientOcclusion.cginc"
ENDCG
}
}
}

View file

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: e881ae5627d1cc84395303acfbca6fb2
timeCreated: 1462280790
licenseType: Store
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,49 @@
Shader "Hidden/Post FX/Blit"
{
Properties
{
_MainTex("Main Texture", 2D) = "white" {}
}
CGINCLUDE
#include "UnityCG.cginc"
#include "Common.cginc"
struct Varyings
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
Varyings VertBlit(AttributesDefault v)
{
Varyings o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = UnityStereoScreenSpaceUVAdjust(v.texcoord, _MainTex_ST);
return o;
}
half4 FragBlit(Varyings i) : SV_Target
{
half4 col = tex2D(_MainTex, i.uv);
return col;
}
ENDCG
SubShader
{
Cull Off ZWrite Off ZTest Always
Pass
{
CGPROGRAM
#pragma vertex VertBlit
#pragma fragment FragBlit
ENDCG
}
}
}

View file

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 7d89469544dfa214eabdbf37fca76f40
timeCreated: 1474297975
licenseType: Store
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,86 @@
#ifndef __BLOOM__
#define __BLOOM__
#include "Common.cginc"
// Brightness function
half Brightness(half3 c)
{
return Max3(c);
}
// 3-tap median filter
half3 Median(half3 a, half3 b, half3 c)
{
return a + b + c - min(min(a, b), c) - max(max(a, b), c);
}
// Downsample with a 4x4 box filter
half3 DownsampleFilter(sampler2D tex, float2 uv, float2 texelSize)
{
float4 d = texelSize.xyxy * float4(-1.0, -1.0, 1.0, 1.0);
half3 s;
s = DecodeHDR(tex2D(tex, uv + d.xy));
s += DecodeHDR(tex2D(tex, uv + d.zy));
s += DecodeHDR(tex2D(tex, uv + d.xw));
s += DecodeHDR(tex2D(tex, uv + d.zw));
return s * (1.0 / 4.0);
}
// Downsample with a 4x4 box filter + anti-flicker filter
half3 DownsampleAntiFlickerFilter(sampler2D tex, float2 uv, float2 texelSize)
{
float4 d = texelSize.xyxy * float4(-1.0, -1.0, 1.0, 1.0);
half3 s1 = DecodeHDR(tex2D(tex, uv + d.xy));
half3 s2 = DecodeHDR(tex2D(tex, uv + d.zy));
half3 s3 = DecodeHDR(tex2D(tex, uv + d.xw));
half3 s4 = DecodeHDR(tex2D(tex, uv + d.zw));
// Karis's luma weighted average (using brightness instead of luma)
half s1w = 1.0 / (Brightness(s1) + 1.0);
half s2w = 1.0 / (Brightness(s2) + 1.0);
half s3w = 1.0 / (Brightness(s3) + 1.0);
half s4w = 1.0 / (Brightness(s4) + 1.0);
half one_div_wsum = 1.0 / (s1w + s2w + s3w + s4w);
return (s1 * s1w + s2 * s2w + s3 * s3w + s4 * s4w) * one_div_wsum;
}
half3 UpsampleFilter(sampler2D tex, float2 uv, float2 texelSize, float sampleScale)
{
#if MOBILE_OR_CONSOLE
// 4-tap bilinear upsampler
float4 d = texelSize.xyxy * float4(-1.0, -1.0, 1.0, 1.0) * (sampleScale * 0.5);
half3 s;
s = DecodeHDR(tex2D(tex, uv + d.xy));
s += DecodeHDR(tex2D(tex, uv + d.zy));
s += DecodeHDR(tex2D(tex, uv + d.xw));
s += DecodeHDR(tex2D(tex, uv + d.zw));
return s * (1.0 / 4.0);
#else
// 9-tap bilinear upsampler (tent filter)
float4 d = texelSize.xyxy * float4(1.0, 1.0, -1.0, 0.0) * sampleScale;
half3 s;
s = DecodeHDR(tex2D(tex, uv - d.xy));
s += DecodeHDR(tex2D(tex, uv - d.wy)) * 2.0;
s += DecodeHDR(tex2D(tex, uv - d.zy));
s += DecodeHDR(tex2D(tex, uv + d.zw)) * 2.0;
s += DecodeHDR(tex2D(tex, uv)) * 4.0;
s += DecodeHDR(tex2D(tex, uv + d.xw)) * 2.0;
s += DecodeHDR(tex2D(tex, uv + d.zy));
s += DecodeHDR(tex2D(tex, uv + d.wy)) * 2.0;
s += DecodeHDR(tex2D(tex, uv + d.xy));
return s * (1.0 / 16.0);
#endif
}
#endif // __BLOOM__

View file

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 7d1f4dd94c8e6e940b0730076ea7d6d9
timeCreated: 1462980395
licenseType: Store
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,182 @@
//
// Kino/Bloom v2 - Bloom filter for Unity
//
// Copyright (C) 2015, 2016 Keijiro Takahashi
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
Shader "Hidden/Post FX/Bloom"
{
Properties
{
_MainTex ("", 2D) = "" {}
_BaseTex ("", 2D) = "" {}
_AutoExposure ("", 2D) = "" {}
}
CGINCLUDE
#pragma target 3.0
#include "UnityCG.cginc"
#include "Bloom.cginc"
#include "Common.cginc"
sampler2D _BaseTex;
float2 _BaseTex_TexelSize;
sampler2D _AutoExposure;
float _PrefilterOffs;
float _Threshold;
float3 _Curve;
float _SampleScale;
// -----------------------------------------------------------------------------
// Vertex shaders
struct VaryingsMultitex
{
float4 pos : SV_POSITION;
float2 uvMain : TEXCOORD0;
float2 uvBase : TEXCOORD1;
};
VaryingsMultitex VertMultitex(AttributesDefault v)
{
VaryingsMultitex o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uvMain = UnityStereoScreenSpaceUVAdjust(v.texcoord.xy, _MainTex_ST);
o.uvBase = o.uvMain;
#if UNITY_UV_STARTS_AT_TOP
if (_BaseTex_TexelSize.y < 0.0)
o.uvBase.y = 1.0 - o.uvBase.y;
#endif
return o;
}
// -----------------------------------------------------------------------------
// Fragment shaders
half4 FetchAutoExposed(sampler2D tex, float2 uv)
{
float autoExposure = 1.0;
uv = UnityStereoScreenSpaceUVAdjust(uv, _MainTex_ST);
autoExposure = tex2D(_AutoExposure, uv).r;
return tex2D(tex, uv) * autoExposure;
}
half4 FragPrefilter(VaryingsDefault i) : SV_Target
{
float2 uv = i.uv + _MainTex_TexelSize.xy * _PrefilterOffs;
#if ANTI_FLICKER
float3 d = _MainTex_TexelSize.xyx * float3(1.0, 1.0, 0.0);
half4 s0 = SafeHDR(FetchAutoExposed(_MainTex, uv));
half3 s1 = SafeHDR(FetchAutoExposed(_MainTex, uv - d.xz).rgb);
half3 s2 = SafeHDR(FetchAutoExposed(_MainTex, uv + d.xz).rgb);
half3 s3 = SafeHDR(FetchAutoExposed(_MainTex, uv - d.zy).rgb);
half3 s4 = SafeHDR(FetchAutoExposed(_MainTex, uv + d.zy).rgb);
half3 m = Median(Median(s0.rgb, s1, s2), s3, s4);
#else
half4 s0 = SafeHDR(FetchAutoExposed(_MainTex, uv));
half3 m = s0.rgb;
#endif
#if UNITY_COLORSPACE_GAMMA
m = GammaToLinearSpace(m);
#endif
// Pixel brightness
half br = Brightness(m);
// Under-threshold part: quadratic curve
half rq = clamp(br - _Curve.x, 0.0, _Curve.y);
rq = _Curve.z * rq * rq;
// Combine and apply the brightness response curve.
m *= max(rq, br - _Threshold) / max(br, 1e-5);
return EncodeHDR(m);
}
half4 FragDownsample1(VaryingsDefault i) : SV_Target
{
#if ANTI_FLICKER
return EncodeHDR(DownsampleAntiFlickerFilter(_MainTex, i.uvSPR, _MainTex_TexelSize.xy));
#else
return EncodeHDR(DownsampleFilter(_MainTex, i.uvSPR, _MainTex_TexelSize.xy));
#endif
}
half4 FragDownsample2(VaryingsDefault i) : SV_Target
{
return EncodeHDR(DownsampleFilter(_MainTex, i.uvSPR, _MainTex_TexelSize.xy));
}
half4 FragUpsample(VaryingsMultitex i) : SV_Target
{
half3 base = DecodeHDR(tex2D(_BaseTex, i.uvBase));
half3 blur = UpsampleFilter(_MainTex, i.uvMain, _MainTex_TexelSize.xy, _SampleScale);
return EncodeHDR(base + blur);
}
ENDCG
SubShader
{
ZTest Always Cull Off ZWrite Off
Pass
{
CGPROGRAM
#pragma multi_compile __ ANTI_FLICKER
#pragma multi_compile __ UNITY_COLORSPACE_GAMMA
#pragma vertex VertDefault
#pragma fragment FragPrefilter
ENDCG
}
Pass
{
CGPROGRAM
#pragma multi_compile __ ANTI_FLICKER
#pragma vertex VertDefault
#pragma fragment FragDownsample1
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex VertDefault
#pragma fragment FragDownsample2
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex VertMultitex
#pragma fragment FragUpsample
ENDCG
}
}
}

View file

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 4ceb73bc148699b469361531d6062548
timeCreated: 1462953634
licenseType: Store
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,257 @@
Shader "Hidden/Post FX/Builtin Debug Views"
{
CGINCLUDE
#include "UnityCG.cginc"
#include "Common.cginc"
#pragma exclude_renderers d3d11_9x
sampler2D_float _CameraDepthTexture;
sampler2D_float _CameraDepthNormalsTexture;
sampler2D_float _CameraMotionVectorsTexture;
float4 _CameraDepthTexture_ST;
float4 _CameraDepthNormalsTexture_ST;
float4 _CameraMotionVectorsTexture_ST;
#if SOURCE_GBUFFER
sampler2D _CameraGBufferTexture2;
float4 _CameraGBufferTexture2_ST;
#endif
// -----------------------------------------------------------------------------
// Depth
float _DepthScale;
float4 FragDepth(VaryingsDefault i) : SV_Target
{
float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, UnityStereoScreenSpaceUVAdjust(i.uv, _CameraDepthTexture_ST));
depth = Linear01Depth(depth) * _DepthScale;
float3 d = depth.xxx;
#if !UNITY_COLORSPACE_GAMMA
d = GammaToLinearSpace(d);
#endif
return float4(d, 1.0);
}
// -----------------------------------------------------------------------------
// Normals
float3 SampleNormal(float2 uv)
{
#if SOURCE_GBUFFER
float3 norm = tex2D(_CameraGBufferTexture2, uv).xyz * 2.0 - 1.0;
return mul((float3x3)unity_WorldToCamera, norm);
#else
float4 cdn = tex2D(_CameraDepthNormalsTexture, uv);
return DecodeViewNormalStereo(cdn) * float3(1.0, 1.0, -1.0);
#endif
}
float4 FragNormals(VaryingsDefault i) : SV_Target
{
float3 n = SampleNormal(UnityStereoScreenSpaceUVAdjust(i.uv, _CameraDepthNormalsTexture_ST));
#if UNITY_COLORSPACE_GAMMA
n = LinearToGammaSpace(n);
#endif
return float4(n, 1.0);
}
// -----------------------------------------------------------------------------
// Motion vectors
float _Opacity;
float _Amplitude;
float4 _Scale;
float4 FragMovecsOpacity(VaryingsDefault i) : SV_Target
{
float4 src = tex2D(_MainTex, i.uv);
return float4(src.rgb * _Opacity, src.a);
}
// Convert a motion vector into RGBA color.
float4 VectorToColor(float2 mv)
{
float phi = atan2(mv.x, mv.y);
float hue = (phi / UNITY_PI + 1.0) * 0.5;
float r = abs(hue * 6.0 - 3.0) - 1.0;
float g = 2.0 - abs(hue * 6.0 - 2.0);
float b = 2.0 - abs(hue * 6.0 - 4.0);
float a = length(mv);
return saturate(float4(r, g, b, a));
}
float4 FragMovecsImaging(VaryingsDefault i) : SV_Target
{
float4 src = tex2D(_MainTex, i.uv);
float2 mv = tex2D(_CameraMotionVectorsTexture, i.uv).rg * _Amplitude;
#if UNITY_UV_STARTS_AT_TOP
mv.y *= -1.0;
#endif
float4 mc = VectorToColor(mv);
float3 rgb = src.rgb;
#if !UNITY_COLORSPACE_GAMMA
rgb = LinearToGammaSpace(rgb);
#endif
rgb = lerp(rgb, mc.rgb, mc.a * _Opacity);
#if !UNITY_COLORSPACE_GAMMA
rgb = GammaToLinearSpace(rgb);
#endif
return float4(rgb, src.a);
}
struct VaryingsArrows
{
float4 vertex : SV_POSITION;
float2 scoord : TEXCOORD;
float4 color : COLOR;
};
VaryingsArrows VertArrows(AttributesDefault v)
{
// Retrieve the motion vector.
float4 uv = float4(v.texcoord.xy, 0.0, 0.0);
#if UNITY_UV_STARTS_AT_TOP
uv.y = 1.0 - uv.y;
#endif
float2 mv = tex2Dlod(_CameraMotionVectorsTexture, uv).rg * _Amplitude;
#if UNITY_UV_STARTS_AT_TOP
mv.y *= -1.0;
#endif
// Arrow color
float4 color = VectorToColor(mv);
// Make a rotation matrix based on the motion vector.
float2x2 rot = float2x2(mv.y, mv.x, -mv.x, mv.y);
// Rotate and scale the body of the arrow.
float2 pos = mul(rot, v.vertex.zy) * _Scale.xy;
// Normalized variant of the motion vector and the rotation matrix.
float2 mv_n = normalize(mv);
float2x2 rot_n = float2x2(mv_n.y, mv_n.x, -mv_n.x, mv_n.y);
// Rotate and scale the head of the arrow.
float2 head = float2(v.vertex.x, -abs(v.vertex.x)) * 0.3;
head *= saturate(color.a);
pos += mul(rot_n, head) * _Scale.xy;
// Offset the arrow position.
pos += v.texcoord.xy * 2.0 - 1.0;
// Convert to the screen coordinates.
float2 scoord = (pos + 1.0) * 0.5 * _ScreenParams.xy;
// Snap to a pixel-perfect position.
scoord = round(scoord);
// Bring back to the normalized screen space.
pos = (scoord + 0.5) * (_ScreenParams.zw - 1.0) * 2.0 - 1.0;
// Color tweaks
color.rgb = GammaToLinearSpace(lerp(color.rgb, 1.0, 0.5));
color.a *= _Opacity;
// Output
VaryingsArrows o;
o.vertex = float4(pos, 0.0, 1.0);
o.scoord = scoord;
o.color = saturate(color);
return o;
}
float4 FragMovecsArrows(VaryingsArrows i) : SV_Target
{
// Pseudo anti-aliasing.
float aa = length(frac(i.scoord) - 0.5) / 0.707;
aa *= (aa * (aa * 0.305306011 + 0.682171111) + 0.012522878); // gamma
return float4(i.color.rgb, i.color.a * aa);
}
ENDCG
SubShader
{
Cull Off ZWrite Off ZTest Always
// (0) - Depth
Pass
{
CGPROGRAM
#pragma vertex VertDefault
#pragma fragment FragDepth
ENDCG
}
// (1) - Normals
Pass
{
CGPROGRAM
#pragma vertex VertDefault
#pragma fragment FragNormals
#pragma multi_compile __ SOURCE_GBUFFER
ENDCG
}
// (2) - Motion vectors - Opacity
Pass
{
CGPROGRAM
#pragma vertex VertDefault
#pragma fragment FragMovecsOpacity
ENDCG
}
// (3) - Motion vectors - Imaging
Pass
{
CGPROGRAM
#pragma vertex VertDefault
#pragma fragment FragMovecsImaging
#pragma multi_compile __ UNITY_COLORSPACE_GAMMA
ENDCG
}
// (4) - Motion vectors - Arrows
Pass
{
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex VertArrows
#pragma fragment FragMovecsArrows
ENDCG
}
}
}

View file

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 72127ba7dd8c6b04bb3f29c7ee669813
timeCreated: 1468224802
licenseType: Store
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,290 @@
#ifndef __COLOR_GRADING__
#define __COLOR_GRADING__
#include "ACES.cginc"
#include "Common.cginc"
// Set to 1 to use more precise but more expensive log/linear conversions. I haven't found a proper
// use case for the high precision version yet so I'm leaving this to 0.
#define COLOR_GRADING_PRECISE_LOG 0
//
// Alexa LogC converters (El 1000)
// See http://www.vocas.nl/webfm_send/964
// It's a good fit to store HDR values in log as the range is pretty wide (1 maps to ~58.85666) and
// is quick enough to compute.
//
struct ParamsLogC
{
half cut;
half a, b, c, d, e, f;
};
static const ParamsLogC LogC =
{
0.011361, // cut
5.555556, // a
0.047996, // b
0.244161, // c
0.386036, // d
5.301883, // e
0.092819 // f
};
half LinearToLogC_Precise(half x)
{
half o;
if (x > LogC.cut)
o = LogC.c * log10(LogC.a * x + LogC.b) + LogC.d;
else
o = LogC.e * x + LogC.f;
return o;
}
half3 LinearToLogC(half3 x)
{
#if COLOR_GRADING_PRECISE_LOG
return half3(
LinearToLogC_Precise(x.x),
LinearToLogC_Precise(x.y),
LinearToLogC_Precise(x.z)
);
#else
return LogC.c * log10(LogC.a * x + LogC.b) + LogC.d;
#endif
}
half LogCToLinear_Precise(half x)
{
half o;
if (x > LogC.e * LogC.cut + LogC.f)
o = (pow(10.0, (x - LogC.d) / LogC.c) - LogC.b) / LogC.a;
else
o = (x - LogC.f) / LogC.e;
return o;
}
half3 LogCToLinear(half3 x)
{
#if COLOR_GRADING_PRECISE_LOG
return half3(
LogCToLinear_Precise(x.x),
LogCToLinear_Precise(x.y),
LogCToLinear_Precise(x.z)
);
#else
return (pow(10.0, (x - LogC.d) / LogC.c) - LogC.b) / LogC.a;
#endif
}
//
// White balance
// Recommended workspace: ACEScg (linear)
//
static const half3x3 LIN_2_LMS_MAT = {
3.90405e-1, 5.49941e-1, 8.92632e-3,
7.08416e-2, 9.63172e-1, 1.35775e-3,
2.31082e-2, 1.28021e-1, 9.36245e-1
};
static const half3x3 LMS_2_LIN_MAT = {
2.85847e+0, -1.62879e+0, -2.48910e-2,
-2.10182e-1, 1.15820e+0, 3.24281e-4,
-4.18120e-2, -1.18169e-1, 1.06867e+0
};
half3 WhiteBalance(half3 c, half3 balance)
{
half3 lms = mul(LIN_2_LMS_MAT, c);
lms *= balance;
return mul(LMS_2_LIN_MAT, lms);
}
//
// Luminance (Rec.709 primaries according to ACES specs)
//
half AcesLuminance(half3 c)
{
return dot(c, half3(0.2126, 0.7152, 0.0722));
}
//
// Offset, Power, Slope (ASC-CDL)
// Works in Log & Linear. Results will be different but still correct.
//
half3 OffsetPowerSlope(half3 c, half3 offset, half3 power, half3 slope)
{
half3 so = c * slope + offset;
so = so > (0.0).xxx ? pow(so, power) : so;
return so;
}
//
// Lift, Gamma (pre-inverted), Gain
// Recommended workspace: ACEScg (linear)
//
half3 LiftGammaGain(half3 c, half3 lift, half3 invgamma, half3 gain)
{
//return gain * (lift * (1.0 - c) + pow(max(c, kEpsilon), invgamma));
//return pow(gain * (c + lift * (1.0 - c)), invgamma);
half3 power = invgamma;
half3 offset = lift * gain;
half3 slope = ((1.0).xxx - lift) * gain;
return OffsetPowerSlope(c, offset, power, slope);
}
//
// Saturation (should be used after offset/power/slope)
// Recommended workspace: ACEScc (log)
// Optimal range: [0.0, 2.0]
//
half3 Saturation(half3 c, half sat)
{
half luma = AcesLuminance(c);
return luma.xxx + sat * (c - luma.xxx);
}
//
// Basic contrast curve
// Recommended workspace: ACEScc (log)
// Optimal range: [0.0, 2.0]
//
half3 ContrastLog(half3 c, half con)
{
return (c - ACEScc_MIDGRAY) * con + ACEScc_MIDGRAY;
}
//
// Hue, Saturation, Value
// Ranges:
// Hue [0.0, 1.0]
// Sat [0.0, 1.0]
// Lum [0.0, HALF_MAX]
//
half3 RgbToHsv(half3 c)
{
half4 K = half4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
half4 p = lerp(half4(c.bg, K.wz), half4(c.gb, K.xy), step(c.b, c.g));
half4 q = lerp(half4(p.xyw, c.r), half4(c.r, p.yzx), step(p.x, c.r));
half d = q.x - min(q.w, q.y);
half e = EPSILON;
return half3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
half3 HsvToRgb(half3 c)
{
half4 K = half4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
half3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * lerp(K.xxx, saturate(p - K.xxx), c.y);
}
half RotateHue(half value, half low, half hi)
{
return (value < low)
? value + hi
: (value > hi)
? value - hi
: value;
}
//
// Remaps Y/R/G/B values
//
half3 YrgbCurve(half3 c, sampler2D curveTex)
{
const float kHalfPixel = (1.0 / 128.0) / 2.0;
// Y
c += kHalfPixel.xxx;
float mr = tex2D(curveTex, float2(c.r, 0.75)).a;
float mg = tex2D(curveTex, float2(c.g, 0.75)).a;
float mb = tex2D(curveTex, float2(c.b, 0.75)).a;
c = saturate(float3(mr, mg, mb));
// RGB
c += kHalfPixel.xxx;
float r = tex2D(curveTex, float2(c.r, 0.75)).r;
float g = tex2D(curveTex, float2(c.g, 0.75)).g;
float b = tex2D(curveTex, float2(c.b, 0.75)).b;
return saturate(half3(r, g, b));
}
//
// (X) Hue VS Hue - Remaps hue on a curve according to the current hue
// Input is Hue [0.0, 1.0]
// Output is Hue [0.0, 1.0]
//
half SecondaryHueHue(half hue, sampler2D curveTex)
{
half offset = saturate(tex2D(curveTex, half2(hue, 0.25)).x) - 0.5;
hue += offset;
hue = RotateHue(hue, 0.0, 1.0);
return hue;
}
//
// (Y) Hue VS Saturation - Remaps saturation on a curve according to the current hue
// Input is Hue [0.0, 1.0]
// Output is Saturation multiplier [0.0, 2.0]
//
half SecondaryHueSat(half hue, sampler2D curveTex)
{
return saturate(tex2D(curveTex, half2(hue, 0.25)).y) * 2.0;
}
//
// (Z) Saturation VS Saturation - Remaps saturation on a curve according to the current saturation
// Input is Saturation [0.0, 1.0]
// Output is Saturation multiplier [0.0, 2.0]
//
half SecondarySatSat(half sat, sampler2D curveTex)
{
return saturate(tex2D(curveTex, half2(sat, 0.25)).z) * 2.0;
}
//
// (W) Luminance VS Saturation - Remaps saturation on a curve according to the current luminance
// Input is Luminance [0.0, 1.0]
// Output is Saturation multiplier [0.0, 2.0]
//
half SecondaryLumSat(half lum, sampler2D curveTex)
{
return saturate(tex2D(curveTex, half2(lum, 0.25)).w) * 2.0;
}
//
// Channel mixing (same as Photoshop's and DaVinci's Resolve)
// Recommended workspace: ACEScg (linear)
// Input mixers should be in range [-2.0;2.0]
//
half3 ChannelMixer(half3 c, half3 red, half3 green, half3 blue)
{
return half3(
dot(c, red),
dot(c, green),
dot(c, blue)
);
}
//
// LUT grading
// scaleOffset = (1 / lut_width, 1 / lut_height, lut_height - 1)
//
half3 ApplyLut2d(sampler2D tex, half3 uvw, half3 scaleOffset)
{
// Strip format where `height = sqrt(width)`
uvw.z *= scaleOffset.z;
half shift = floor(uvw.z);
uvw.xy = uvw.xy * scaleOffset.z * scaleOffset.xy + scaleOffset.xy * 0.5;
uvw.x += shift * scaleOffset.y;
uvw.xyz = lerp(tex2D(tex, uvw.xy).rgb, tex2D(tex, uvw.xy + half2(scaleOffset.y, 0)).rgb, uvw.z - shift);
return uvw;
}
half3 ApplyLut3d(sampler3D tex, half3 uvw)
{
return tex3D(tex, uvw).rgb;
}
#endif // __COLOR_GRADING__

View file

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 26a62c2e30be83547bdfa9fe837165e3
timeCreated: 1460363486
licenseType: Store
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,166 @@
#ifndef __COMMON__
#define __COMMON__
#include "UnityCG.cginc"
// Mobile: use RGBM instead of float/half RGB
#define USE_RGBM defined(SHADER_API_MOBILE)
#define MOBILE_OR_CONSOLE (defined(SHADER_API_MOBILE) || defined(SHADER_API_PSSL) || defined(SHADER_API_XBOXONE) || defined(SHADER_API_WIIU))
#if defined(SHADER_API_PSSL)
// No support for sampler2D_half on PS4 in 5.4
#define sampler2D_half sampler2D_float
#endif
// -----------------------------------------------------------------------------
// Uniforms
#if defined(SEPARATE_TEXTURE_SAMPLER)
Texture2D _MainTex;
SamplerState sampler_MainTex;
#else
sampler2D _MainTex;
#endif
float4 _MainTex_TexelSize;
float4 _MainTex_ST;
// -----------------------------------------------------------------------------
// Vertex shaders
struct AttributesDefault
{
float4 vertex : POSITION;
float4 texcoord : TEXCOORD0;
};
struct VaryingsDefault
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float2 uvSPR : TEXCOORD1; // Single Pass Stereo UVs
};
VaryingsDefault VertDefault(AttributesDefault v)
{
VaryingsDefault o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord.xy;
o.uvSPR = UnityStereoScreenSpaceUVAdjust(v.texcoord.xy, _MainTex_ST);
return o;
}
// -----------------------------------------------------------------------------
// Maths stuff
#define HALF_MAX 65504.0
#define EPSILON 1.0e-4
#define UNITY_PI_2 (UNITY_PI * 2.0)
inline half Min3(half3 x) { return min(x.x, min(x.y, x.z)); }
inline half Min3(half x, half y, half z) { return min(x, min(y, z)); }
inline half Max3(half3 x) { return max(x.x, max(x.y, x.z)); }
inline half Max3(half x, half y, half z) { return max(x, max(y, z)); }
inline half Min4(half4 x) { return min(x.x, min(x.y, min(x.z, x.w))); }
inline half Min4(half x, half y, half z, half w) { return min(x, min(y, min(z, w))); }
inline half Max4(half4 x) { return max(x.x, max(x.y, max(x.z, x.w))); }
inline half Max4(half x, half y, half z, half w) { return max(x, max(y, min(z, w))); }
inline half Pow2(half x) { return x * x; }
inline half2 Pow2(half2 x) { return x * x; }
inline half3 Pow2(half3 x) { return x * x; }
inline half4 Pow2(half4 x) { return x * x; }
inline half Pow3(half x) { return x * x * x; }
inline half2 Pow3(half2 x) { return x * x * x; }
inline half3 Pow3(half3 x) { return x * x * x; }
inline half4 Pow3(half4 x) { return x * x * x; }
#ifndef UNITY_STANDARD_BRDF_INCLUDED
inline half Pow4(half x) { return x * x * x * x; }
inline half2 Pow4(half2 x) { return x * x * x * x; }
inline half3 Pow4(half3 x) { return x * x * x * x; }
inline half4 Pow4(half4 x) { return x * x * x * x; }
#endif
// Returns the largest vector of v1 and v2
inline half2 MaxV(half2 v1, half2 v2) { return dot(v1, v1) < dot(v2, v2) ? v2 : v1; }
inline half3 MaxV(half3 v1, half3 v2) { return dot(v1, v1) < dot(v2, v2) ? v2 : v1; }
inline half4 MaxV(half4 v1, half4 v2) { return dot(v1, v1) < dot(v2, v2) ? v2 : v1; }
// Clamp HDR value within a safe range
inline half SafeHDR(half c) { return min(c, HALF_MAX); }
inline half2 SafeHDR(half2 c) { return min(c, HALF_MAX); }
inline half3 SafeHDR(half3 c) { return min(c, HALF_MAX); }
inline half4 SafeHDR(half4 c) { return min(c, HALF_MAX); }
// Compatibility function
#if (SHADER_TARGET < 50 && !defined(SHADER_API_PSSL))
float rcp(float value)
{
return 1.0 / value;
}
#endif
// Tonemapper from http://gpuopen.com/optimized-reversible-tonemapper-for-resolve/
float4 FastToneMap(in float4 color)
{
return float4(color.rgb * rcp(Max3(color.rgb) + 1.), color.a);
}
float4 FastToneMap(in float4 color, in float weight)
{
return float4(color.rgb * rcp(weight * Max3(color.rgb) + 1.), color.a);
}
float4 FastToneUnmap(in float4 color)
{
return float4(color.rgb * rcp(1. - Max3(color.rgb)), color.a);
}
// Interleaved gradient function from Jimenez 2014 http://goo.gl/eomGso
float GradientNoise(float2 uv)
{
uv = floor(uv * _ScreenParams.xy);
float f = dot(float2(0.06711056, 0.00583715), uv);
return frac(52.9829189 * frac(f));
}
// Z buffer depth to linear 0-1 depth
// Handles orthographic projection correctly
float LinearizeDepth(float z)
{
float isOrtho = unity_OrthoParams.w;
float isPers = 1.0 - unity_OrthoParams.w;
z *= _ZBufferParams.x;
return (1.0 - isOrtho * z) / (isPers * z + _ZBufferParams.y);
}
// -----------------------------------------------------------------------------
// RGBM encoding/decoding
half4 EncodeHDR(float3 rgb)
{
#if USE_RGBM
rgb *= 1.0 / 8.0;
float m = max(max(rgb.r, rgb.g), max(rgb.b, 1e-6));
m = ceil(m * 255.0) / 255.0;
return half4(rgb / m, m);
#else
return half4(rgb, 0.0);
#endif
}
float3 DecodeHDR(half4 rgba)
{
#if USE_RGBM
return rgba.rgb * rgba.a * 8.0;
#else
return rgba.rgb;
#endif
}
#endif // __COMMON__

View file

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: eb88496804341c648b32a75843d92ccb
timeCreated: 1465205118
licenseType: Store
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,243 @@
#ifndef __DEPTH_OF_FIELD__
#define __DEPTH_OF_FIELD__
#if SHADER_TARGET >= 50
// Use separate texture/sampler objects on Shader Model 5.0
#define SEPARATE_TEXTURE_SAMPLER
#define DOF_DECL_TEX2D(tex) Texture2D tex; SamplerState sampler##tex
#define DOF_TEX2D(tex, coord) tex.Sample(sampler##tex, coord)
#else
#define DOF_DECL_TEX2D(tex) sampler2D tex
#define DOF_TEX2D(tex, coord) tex2D(tex, coord)
#endif
#include "Common.cginc"
#include "DiskKernels.cginc"
DOF_DECL_TEX2D(_CameraDepthTexture);
DOF_DECL_TEX2D(_CameraMotionVectorsTexture);
DOF_DECL_TEX2D(_CoCTex);
// Camera parameters
float _Distance;
float _LensCoeff; // f^2 / (N * (S1 - f) * film_width * 2)
float _MaxCoC;
float _RcpMaxCoC;
float _RcpAspect;
half3 _TaaParams; // Jitter.x, Jitter.y, Blending
struct VaryingsDOF
{
float4 pos : SV_POSITION;
half2 uv : TEXCOORD0;
half2 uvAlt : TEXCOORD1;
};
// Common vertex shader with single pass stereo rendering support
VaryingsDOF VertDOF(AttributesDefault v)
{
half2 uvAlt = v.texcoord;
#if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y < 0.0) uvAlt.y = 1.0 - uvAlt.y;
#endif
VaryingsDOF o;
o.pos = UnityObjectToClipPos(v.vertex);
#if defined(UNITY_SINGLE_PASS_STEREO)
o.uv = UnityStereoScreenSpaceUVAdjust(v.texcoord, _MainTex_ST);
o.uvAlt = UnityStereoScreenSpaceUVAdjust(uvAlt, _MainTex_ST);
#else
o.uv = v.texcoord;
o.uvAlt = uvAlt;
#endif
return o;
}
// CoC calculation
half4 FragCoC(VaryingsDOF i) : SV_Target
{
float depth = LinearEyeDepth(DOF_TEX2D(_CameraDepthTexture, i.uv));
half coc = (depth - _Distance) * _LensCoeff / max(depth, 1e-5);
return saturate(coc * 0.5 * _RcpMaxCoC + 0.5);
}
// Temporal filter
half4 FragTempFilter(VaryingsDOF i) : SV_Target
{
float3 uvOffs = _MainTex_TexelSize.xyy * float3(1, 1, 0);
#if defined(SEPARATE_TEXTURE_SAMPLER)
half4 cocTL = _CoCTex.GatherRed(sampler_CoCTex, i.uv - uvOffs.xy * 0.5); // top-left
half4 cocBR = _CoCTex.GatherRed(sampler_CoCTex, i.uv + uvOffs.xy * 0.5); // bottom-right
half coc1 = cocTL.x; // top
half coc2 = cocTL.z; // left
half coc3 = cocBR.x; // bottom
half coc4 = cocBR.z; // right
#else
half coc1 = DOF_TEX2D(_CoCTex, i.uv - uvOffs.xz).r; // top
half coc2 = DOF_TEX2D(_CoCTex, i.uv - uvOffs.zy).r; // left
half coc3 = DOF_TEX2D(_CoCTex, i.uv + uvOffs.zy).r; // bottom
half coc4 = DOF_TEX2D(_CoCTex, i.uv + uvOffs.xz).r; // right
#endif
// Dejittered center sample.
half coc0 = DOF_TEX2D(_CoCTex, i.uv - _TaaParams.xy).r;
// CoC dilation: determine the closest point in the four neighbors.
float3 closest = float3(0, 0, coc0);
closest = coc1 < closest.z ? float3(-uvOffs.xz, coc1) : closest;
closest = coc2 < closest.z ? float3(-uvOffs.zy, coc2) : closest;
closest = coc3 < closest.z ? float3(+uvOffs.zy, coc3) : closest;
closest = coc4 < closest.z ? float3(+uvOffs.xz, coc4) : closest;
// Sample the history buffer with the motion vector at the closest point.
float2 motion = DOF_TEX2D(_CameraMotionVectorsTexture, i.uv + closest.xy).xy;
half cocHis = DOF_TEX2D(_MainTex, i.uv - motion).r;
// Neighborhood clamping.
half cocMin = closest.z;
half cocMax = max(max(max(max(coc0, coc1), coc2), coc3), coc4);
cocHis = clamp(cocHis, cocMin, cocMax);
// Blend with the history.
return lerp(coc0, cocHis, _TaaParams.z);
}
// Prefilter: downsampling and premultiplying.
half4 FragPrefilter(VaryingsDOF i) : SV_Target
{
#if defined(SEPARATE_TEXTURE_SAMPLER)
// Sample source colors.
half4 c_r = _MainTex.GatherRed (sampler_MainTex, i.uv);
half4 c_g = _MainTex.GatherGreen(sampler_MainTex, i.uv);
half4 c_b = _MainTex.GatherBlue (sampler_MainTex, i.uv);
half3 c0 = half3(c_r.x, c_g.x, c_b.x);
half3 c1 = half3(c_r.y, c_g.y, c_b.y);
half3 c2 = half3(c_r.z, c_g.z, c_b.z);
half3 c3 = half3(c_r.w, c_g.w, c_b.w);
// Sample CoCs.
half4 cocs = _CoCTex.Gather(sampler_CoCTex, i.uvAlt) * 2.0 - 1.0;
half coc0 = cocs.x;
half coc1 = cocs.y;
half coc2 = cocs.z;
half coc3 = cocs.w;
#else
float3 duv = _MainTex_TexelSize.xyx * float3(0.5, 0.5, -0.5);
// Sample source colors.
half3 c0 = DOF_TEX2D(_MainTex, i.uv - duv.xy).rgb;
half3 c1 = DOF_TEX2D(_MainTex, i.uv - duv.zy).rgb;
half3 c2 = DOF_TEX2D(_MainTex, i.uv + duv.zy).rgb;
half3 c3 = DOF_TEX2D(_MainTex, i.uv + duv.xy).rgb;
// Sample CoCs.
half coc0 = DOF_TEX2D(_CoCTex, i.uvAlt - duv.xy).r * 2.0 - 1.0;
half coc1 = DOF_TEX2D(_CoCTex, i.uvAlt - duv.zy).r * 2.0 - 1.0;
half coc2 = DOF_TEX2D(_CoCTex, i.uvAlt + duv.zy).r * 2.0 - 1.0;
half coc3 = DOF_TEX2D(_CoCTex, i.uvAlt + duv.xy).r * 2.0 - 1.0;
#endif
// Apply CoC and luma weights to reduce bleeding and flickering.
float w0 = abs(coc0) / (Max3(c0) + 1.0);
float w1 = abs(coc1) / (Max3(c1) + 1.0);
float w2 = abs(coc2) / (Max3(c2) + 1.0);
float w3 = abs(coc3) / (Max3(c3) + 1.0);
// Weighted average of the color samples
half3 avg = c0 * w0 + c1 * w1 + c2 * w2 + c3 * w3;
avg /= max(w0 + w1 + w2 + w3, 1e-5);
// Select the largest CoC value.
half coc_min = Min4(coc0, coc1, coc2, coc3);
half coc_max = Max4(coc0, coc1, coc2, coc3);
half coc = (-coc_min > coc_max ? coc_min : coc_max) * _MaxCoC;
// Premultiply CoC again.
avg *= smoothstep(0, _MainTex_TexelSize.y * 2, abs(coc));
#if defined(UNITY_COLORSPACE_GAMMA)
avg = GammaToLinearSpace(avg);
#endif
return half4(avg, coc);
}
// Bokeh filter with disk-shaped kernels
half4 FragBlur(VaryingsDOF i) : SV_Target
{
half4 samp0 = DOF_TEX2D(_MainTex, i.uv);
half4 bgAcc = 0.0; // Background: far field bokeh
half4 fgAcc = 0.0; // Foreground: near field bokeh
UNITY_LOOP for (int si = 0; si < kSampleCount; si++)
{
float2 disp = kDiskKernel[si] * _MaxCoC;
float dist = length(disp);
float2 duv = float2(disp.x * _RcpAspect, disp.y);
half4 samp = DOF_TEX2D(_MainTex, i.uv + duv);
// BG: Compare CoC of the current sample and the center sample
// and select smaller one.
half bgCoC = max(min(samp0.a, samp.a), 0.0);
// Compare the CoC to the sample distance.
// Add a small margin to smooth out.
const half margin = _MainTex_TexelSize.y * 2;
half bgWeight = saturate((bgCoC - dist + margin) / margin);
half fgWeight = saturate((-samp.a - dist + margin) / margin);
// Cut influence from focused areas because they're darkened by CoC
// premultiplying. This is only needed for near field.
fgWeight *= step(_MainTex_TexelSize.y, -samp.a);
// Accumulation
bgAcc += half4(samp.rgb, 1.0) * bgWeight;
fgAcc += half4(samp.rgb, 1.0) * fgWeight;
}
// Get the weighted average.
bgAcc.rgb /= bgAcc.a + (bgAcc.a == 0.0); // zero-div guard
fgAcc.rgb /= fgAcc.a + (fgAcc.a == 0.0);
// BG: Calculate the alpha value only based on the center CoC.
// This is a rather aggressive approximation but provides stable results.
bgAcc.a = smoothstep(_MainTex_TexelSize.y, _MainTex_TexelSize.y * 2.0, samp0.a);
// FG: Normalize the total of the weights.
fgAcc.a *= UNITY_PI / kSampleCount;
// Alpha premultiplying
half alpha = saturate(fgAcc.a);
half3 rgb = lerp(bgAcc.rgb, fgAcc.rgb, alpha);
return half4(rgb, alpha);
}
// Postfilter blur
half4 FragPostBlur(VaryingsDOF i) : SV_Target
{
// 9 tap tent filter with 4 bilinear samples
const float4 duv = _MainTex_TexelSize.xyxy * float4(0.5, 0.5, -0.5, 0);
half4 acc;
acc = DOF_TEX2D(_MainTex, i.uv - duv.xy);
acc += DOF_TEX2D(_MainTex, i.uv - duv.zy);
acc += DOF_TEX2D(_MainTex, i.uv + duv.zy);
acc += DOF_TEX2D(_MainTex, i.uv + duv.xy);
return acc / 4.0;
}
#endif // __DEPTH_OF_FIELD__

View file

@ -0,0 +1,243 @@
#ifndef __DEPTH_OF_FIELD__
#define __DEPTH_OF_FIELD__
#if SHADER_TARGET >= 50
// Use separate texture/sampler objects on Shader Model 5.0
#define SEPARATE_TEXTURE_SAMPLER
#define DOF_DECL_TEX2D(tex) Texture2D tex; SamplerState sampler##tex
#define DOF_TEX2D(tex, coord) tex.Sample(sampler##tex, coord)
#else
#define DOF_DECL_TEX2D(tex) sampler2D tex
#define DOF_TEX2D(tex, coord) tex2D(tex, coord)
#endif
#include "Common.cginc"
#include "DiskKernels.cginc"
DOF_DECL_TEX2D(_CameraDepthTexture);
DOF_DECL_TEX2D(_CameraMotionVectorsTexture);
DOF_DECL_TEX2D(_CoCTex);
// Camera parameters
float _Distance;
float _LensCoeff; // f^2 / (N * (S1 - f) * film_width * 2)
float _MaxCoC;
float _RcpMaxCoC;
float _RcpAspect;
half3 _TaaParams; // Jitter.x, Jitter.y, Blending
struct VaryingsDOF
{
float4 pos : SV_POSITION;
half2 uv : TEXCOORD0;
half2 uvAlt : TEXCOORD1;
};
// Common vertex shader with single pass stereo rendering support
VaryingsDOF VertDOF(AttributesDefault v)
{
half2 uvAlt = v.texcoord;
#if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y < 0.0) uvAlt.y = 1.0 - uvAlt.y;
#endif
VaryingsDOF o;
o.pos = UnityObjectToClipPos(v.vertex);
#if defined(UNITY_SINGLE_PASS_STEREO)
o.uv = UnityStereoScreenSpaceUVAdjust(v.texcoord, _MainTex_ST);
o.uvAlt = UnityStereoScreenSpaceUVAdjust(uvAlt, _MainTex_ST);
#else
o.uv = v.texcoord;
o.uvAlt = uvAlt;
#endif
return o;
}
// CoC calculation
half4 FragCoC(VaryingsDOF i) : SV_Target
{
float depth = LinearEyeDepth(DOF_TEX2D(_CameraDepthTexture, i.uv));
half coc = (depth - _Distance) * _LensCoeff / max(depth, 1e-5);
return saturate(coc * 0.5 * _RcpMaxCoC + 0.5);
}
// Temporal filter
half4 FragTempFilter(VaryingsDOF i) : SV_Target
{
float3 uvOffs = _MainTex_TexelSize.xyy * float3(1, 1, 0);
#if defined(SEPARATE_TEXTURE_SAMPLER)
half4 cocTL = _CoCTex.GatherRed(sampler_CoCTex, i.uv - uvOffs.xy * 0.5); // top-left
half4 cocBR = _CoCTex.GatherRed(sampler_CoCTex, i.uv + uvOffs.xy * 0.5); // bottom-right
half coc1 = cocTL.x; // top
half coc2 = cocTL.z; // left
half coc3 = cocBR.x; // bottom
half coc4 = cocBR.z; // right
#else
half coc1 = DOF_TEX2D(_CoCTex, i.uv - uvOffs.xz).r; // top
half coc2 = DOF_TEX2D(_CoCTex, i.uv - uvOffs.zy).r; // left
half coc3 = DOF_TEX2D(_CoCTex, i.uv + uvOffs.zy).r; // bottom
half coc4 = DOF_TEX2D(_CoCTex, i.uv + uvOffs.xz).r; // right
#endif
// Dejittered center sample.
half coc0 = DOF_TEX2D(_CoCTex, i.uv - _TaaParams.xy).r;
// CoC dilation: determine the closest point in the four neighbors.
float3 closest = float3(0, 0, coc0);
closest = coc1 < closest.z ? float3(-uvOffs.xz, coc1) : closest;
closest = coc2 < closest.z ? float3(-uvOffs.zy, coc2) : closest;
closest = coc3 < closest.z ? float3(+uvOffs.zy, coc3) : closest;
closest = coc4 < closest.z ? float3(+uvOffs.xz, coc4) : closest;
// Sample the history buffer with the motion vector at the closest point.
float2 motion = DOF_TEX2D(_CameraMotionVectorsTexture, i.uv + closest.xy).xy;
half cocHis = DOF_TEX2D(_MainTex, i.uv - motion).r;
// Neighborhood clamping.
half cocMin = closest.z;
half cocMax = max(max(max(max(coc0, coc1), coc2), coc3), coc4);
cocHis = clamp(cocHis, cocMin, cocMax);
// Blend with the history.
return lerp(coc0, cocHis, _TaaParams.z);
}
// Prefilter: downsampling and premultiplying.
half4 FragPrefilter(VaryingsDOF i) : SV_Target
{
#if defined(SEPARATE_TEXTURE_SAMPLER)
// Sample source colors.
half4 c_r = _MainTex.GatherRed (sampler_MainTex, i.uv);
half4 c_g = _MainTex.GatherGreen(sampler_MainTex, i.uv);
half4 c_b = _MainTex.GatherBlue (sampler_MainTex, i.uv);
half3 c0 = half3(c_r.x, c_g.x, c_b.x);
half3 c1 = half3(c_r.y, c_g.y, c_b.y);
half3 c2 = half3(c_r.z, c_g.z, c_b.z);
half3 c3 = half3(c_r.w, c_g.w, c_b.w);
// Sample CoCs.
half4 cocs = _CoCTex.Gather(sampler_CoCTex, i.uvAlt) * 2.0 - 1.0;
half coc0 = cocs.x;
half coc1 = cocs.y;
half coc2 = cocs.z;
half coc3 = cocs.w;
#else
float3 duv = _MainTex_TexelSize.xyx * float3(0.5, 0.5, -0.5);
// Sample source colors.
half3 c0 = DOF_TEX2D(_MainTex, i.uv - duv.xy).rgb;
half3 c1 = DOF_TEX2D(_MainTex, i.uv - duv.zy).rgb;
half3 c2 = DOF_TEX2D(_MainTex, i.uv + duv.zy).rgb;
half3 c3 = DOF_TEX2D(_MainTex, i.uv + duv.xy).rgb;
// Sample CoCs.
half coc0 = DOF_TEX2D(_CoCTex, i.uvAlt - duv.xy).r * 2.0 - 1.0;
half coc1 = DOF_TEX2D(_CoCTex, i.uvAlt - duv.zy).r * 2.0 - 1.0;
half coc2 = DOF_TEX2D(_CoCTex, i.uvAlt + duv.zy).r * 2.0 - 1.0;
half coc3 = DOF_TEX2D(_CoCTex, i.uvAlt + duv.xy).r * 2.0 - 1.0;
#endif
// Apply CoC and luma weights to reduce bleeding and flickering.
float w0 = abs(coc0) / (Max3(c0) + 1.0);
float w1 = abs(coc1) / (Max3(c1) + 1.0);
float w2 = abs(coc2) / (Max3(c2) + 1.0);
float w3 = abs(coc3) / (Max3(c3) + 1.0);
// Weighted average of the color samples
half3 avg = c0 * w0 + c1 * w1 + c2 * w2 + c3 * w3;
avg /= max(w0 + w1 + w2 + w3, 1e-5);
// Select the largest CoC value.
half coc_min = Min4(coc0, coc1, coc2, coc3);
half coc_max = Max4(coc0, coc1, coc2, coc3);
half coc = (-coc_min > coc_max ? coc_min : coc_max) * _MaxCoC;
// Premultiply CoC again.
avg *= smoothstep(0, _MainTex_TexelSize.y * 2, abs(coc));
#if defined(UNITY_COLORSPACE_GAMMA)
avg = GammaToLinearSpace(avg);
#endif
return half4(avg, coc);
}
// Bokeh filter with disk-shaped kernels
half4 FragBlur(VaryingsDOF i) : SV_Target
{
half4 samp0 = DOF_TEX2D(_MainTex, i.uv);
half4 bgAcc = 0.0; // Background: far field bokeh
half4 fgAcc = 0.0; // Foreground: near field bokeh
UNITY_LOOP for (int si = 0; si < kSampleCount; si++)
{
float2 disp = kDiskKernel[si] * _MaxCoC;
float dist = length(disp);
float2 duv = float2(disp.x * _RcpAspect, disp.y);
half4 samp = DOF_TEX2D(_MainTex, i.uv + duv);
// BG: Compare CoC of the current sample and the center sample
// and select smaller one.
half bgCoC = max(min(samp0.a, samp.a), 0.0);
// Compare the CoC to the sample distance.
// Add a small margin to smooth out.
const half margin = _MainTex_TexelSize.y * 2;
half bgWeight = saturate((bgCoC - dist + margin) / margin);
half fgWeight = saturate((-samp.a - dist + margin) / margin);
// Cut influence from focused areas because they're darkened by CoC
// premultiplying. This is only needed for near field.
fgWeight *= step(_MainTex_TexelSize.y, -samp.a);
// Accumulation
bgAcc += half4(samp.rgb, 1.0) * bgWeight;
fgAcc += half4(samp.rgb, 1.0) * fgWeight;
}
// Get the weighted average.
bgAcc.rgb /= bgAcc.a + (bgAcc.a == 0.0); // zero-div guard
fgAcc.rgb /= fgAcc.a + (fgAcc.a == 0.0);
// BG: Calculate the alpha value only based on the center CoC.
// This is a rather aggressive approximation but provides stable results.
bgAcc.a = smoothstep(_MainTex_TexelSize.y, _MainTex_TexelSize.y * 2.0, samp0.a);
// FG: Normalize the total of the weights.
fgAcc.a *= UNITY_PI / kSampleCount;
// Alpha premultiplying
half alpha = saturate(fgAcc.a);
half3 rgb = lerp(bgAcc.rgb, fgAcc.rgb, alpha);
return half4(rgb, alpha);
}
// Postfilter blur
half4 FragPostBlur(VaryingsDOF i) : SV_Target
{
// 9 tap tent filter with 4 bilinear samples
const float4 duv = _MainTex_TexelSize.xyxy * float4(0.5, 0.5, -0.5, 0);
half4 acc;
acc = DOF_TEX2D(_MainTex, i.uv - duv.xy);
acc += DOF_TEX2D(_MainTex, i.uv - duv.zy);
acc += DOF_TEX2D(_MainTex, i.uv + duv.zy);
acc += DOF_TEX2D(_MainTex, i.uv + duv.xy);
return acc / 4.0;
}
#endif // __DEPTH_OF_FIELD__

Some files were not shown because too many files have changed in this diff Show more