diff --git a/shaders/ReShade.fxh b/shaders/ReShade.fxh new file mode 100644 index 0000000..1cd8205 --- /dev/null +++ b/shaders/ReShade.fxh @@ -0,0 +1,113 @@ +#pragma once + +#if !defined(__RESHADE__) || __RESHADE__ < 30000 + #error "ReShade 3.0+ is required to use this header file" +#endif + +#ifndef RESHADE_DEPTH_INPUT_IS_UPSIDE_DOWN + #define RESHADE_DEPTH_INPUT_IS_UPSIDE_DOWN 0 +#endif +#ifndef RESHADE_DEPTH_INPUT_IS_REVERSED + #define RESHADE_DEPTH_INPUT_IS_REVERSED 1 +#endif +#ifndef RESHADE_DEPTH_INPUT_IS_LOGARITHMIC + #define RESHADE_DEPTH_INPUT_IS_LOGARITHMIC 0 +#endif + +#ifndef RESHADE_DEPTH_MULTIPLIER + #define RESHADE_DEPTH_MULTIPLIER 1 +#endif +#ifndef RESHADE_DEPTH_LINEARIZATION_FAR_PLANE + #define RESHADE_DEPTH_LINEARIZATION_FAR_PLANE 1000.0 +#endif + +// Above 1 expands coordinates, below 1 contracts and 1 is equal to no scaling on any axis +#ifndef RESHADE_DEPTH_INPUT_Y_SCALE + #define RESHADE_DEPTH_INPUT_Y_SCALE 1 +#endif +#ifndef RESHADE_DEPTH_INPUT_X_SCALE + #define RESHADE_DEPTH_INPUT_X_SCALE 1 +#endif +// An offset to add to the Y coordinate, (+) = move up, (-) = move down +#ifndef RESHADE_DEPTH_INPUT_Y_OFFSET + #define RESHADE_DEPTH_INPUT_Y_OFFSET 0 +#endif +#ifndef RESHADE_DEPTH_INPUT_Y_PIXEL_OFFSET + #define RESHADE_DEPTH_INPUT_Y_PIXEL_OFFSET 0 +#endif +// An offset to add to the X coordinate, (+) = move right, (-) = move left +#ifndef RESHADE_DEPTH_INPUT_X_OFFSET + #define RESHADE_DEPTH_INPUT_X_OFFSET 0 +#endif +#ifndef RESHADE_DEPTH_INPUT_X_PIXEL_OFFSET + #define RESHADE_DEPTH_INPUT_X_PIXEL_OFFSET 0 +#endif + +#define BUFFER_PIXEL_SIZE float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT) +#define BUFFER_SCREEN_SIZE float2(BUFFER_WIDTH, BUFFER_HEIGHT) +#define BUFFER_ASPECT_RATIO (BUFFER_WIDTH * BUFFER_RCP_HEIGHT) + +namespace ReShade +{ +#if defined(__RESHADE_FXC__) + float GetAspectRatio() { return BUFFER_WIDTH * BUFFER_RCP_HEIGHT; } + float2 GetPixelSize() { return float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT); } + float2 GetScreenSize() { return float2(BUFFER_WIDTH, BUFFER_HEIGHT); } + #define AspectRatio GetAspectRatio() + #define PixelSize GetPixelSize() + #define ScreenSize GetScreenSize() +#else + // These are deprecated and will be removed eventually. + static const float AspectRatio = BUFFER_WIDTH * BUFFER_RCP_HEIGHT; + static const float2 PixelSize = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT); + static const float2 ScreenSize = float2(BUFFER_WIDTH, BUFFER_HEIGHT); +#endif + + // Global textures and samplers + texture BackBufferTex : COLOR; + texture DepthBufferTex : DEPTH; + + sampler BackBuffer { Texture = BackBufferTex; }; + sampler DepthBuffer { Texture = DepthBufferTex; }; + + // Helper functions + float GetLinearizedDepth(float2 texcoord) + { +#if RESHADE_DEPTH_INPUT_IS_UPSIDE_DOWN + texcoord.y = 1.0 - texcoord.y; +#endif + texcoord.x /= RESHADE_DEPTH_INPUT_X_SCALE; + texcoord.y /= RESHADE_DEPTH_INPUT_Y_SCALE; +#if RESHADE_DEPTH_INPUT_X_PIXEL_OFFSET + texcoord.x -= RESHADE_DEPTH_INPUT_X_PIXEL_OFFSET * BUFFER_RCP_WIDTH; +#else // Do not check RESHADE_DEPTH_INPUT_X_OFFSET, since it may be a decimal number, which the preprocessor cannot handle + texcoord.x -= RESHADE_DEPTH_INPUT_X_OFFSET / 2.000000001; +#endif +#if RESHADE_DEPTH_INPUT_Y_PIXEL_OFFSET + texcoord.y += RESHADE_DEPTH_INPUT_Y_PIXEL_OFFSET * BUFFER_RCP_HEIGHT; +#else + texcoord.y += RESHADE_DEPTH_INPUT_Y_OFFSET / 2.000000001; +#endif + float depth = tex2Dlod(DepthBuffer, float4(texcoord, 0, 0)).x * RESHADE_DEPTH_MULTIPLIER; + +#if RESHADE_DEPTH_INPUT_IS_LOGARITHMIC + const float C = 0.01; + depth = (exp(depth * log(C + 1.0)) - 1.0) / C; +#endif +#if RESHADE_DEPTH_INPUT_IS_REVERSED + depth = 1.0 - depth; +#endif + const float N = 1.0; + depth /= RESHADE_DEPTH_LINEARIZATION_FAR_PLANE - depth * (RESHADE_DEPTH_LINEARIZATION_FAR_PLANE - N); + + return depth; + } +} + +// Vertex shader generating a triangle covering the entire screen +void PostProcessVS(in uint id : SV_VertexID, out float4 position : SV_Position, out float2 texcoord : TEXCOORD) +{ + texcoord.x = (id == 2) ? 2.0 : 0.0; + texcoord.y = (id == 1) ? 2.0 : 0.0; + position = float4(texcoord * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); +} diff --git a/shaders/cBloom.fx b/shaders/cBloom.fx index fc86229..217c954 100644 --- a/shaders/cBloom.fx +++ b/shaders/cBloom.fx @@ -27,22 +27,22 @@ uniform float _Intensity < texture2D _RenderColor : COLOR; sampler2D _SampleColor { Texture = _RenderColor; SRGBTexture = TRUE; }; -texture2D _RenderBloom1 { Width = BUFFER_WIDTH / 2; Height = BUFFER_HEIGHT / 2; Format = RGBA16F; }; +texture2D _RenderBloom1 { Width = BUFFER_WIDTH / 2; Height = BUFFER_HEIGHT / 2; Format = RGBA16F; }; sampler2D _SampleBloom1 { Texture = _RenderBloom1; }; -texture2D _RenderBloom2 { Width = BUFFER_WIDTH / 4; Height = BUFFER_HEIGHT / 4; Format = RGBA16F; }; +texture2D _RenderBloom2 { Width = BUFFER_WIDTH / 4; Height = BUFFER_HEIGHT / 4; Format = RGBA16F; }; sampler2D _SampleBloom2 { Texture = _RenderBloom2; }; -texture2D _RenderBloom3 { Width = BUFFER_WIDTH / 8; Height = BUFFER_HEIGHT / 8; Format = RGBA16F; }; +texture2D _RenderBloom3 { Width = BUFFER_WIDTH / 8; Height = BUFFER_HEIGHT / 8; Format = RGBA16F; }; sampler2D _SampleBloom3 { Texture = _RenderBloom3; }; -texture2D _RenderBloom4 { Width = BUFFER_WIDTH / 16; Height = BUFFER_HEIGHT / 16; Format = RGBA16F; }; +texture2D _RenderBloom4 { Width = BUFFER_WIDTH / 16; Height = BUFFER_HEIGHT / 16; Format = RGBA16F; }; sampler2D _SampleBloom4 { Texture = _RenderBloom4; }; -texture2D _RenderBloom5 { Width = BUFFER_WIDTH / 32; Height = BUFFER_HEIGHT / 32; Format = RGBA16F; }; +texture2D _RenderBloom5 { Width = BUFFER_WIDTH / 32; Height = BUFFER_HEIGHT / 32; Format = RGBA16F; }; sampler2D _SampleBloom5 { Texture = _RenderBloom5; }; -texture2D _RenderBloom6 { Width = BUFFER_WIDTH / 64; Height = BUFFER_HEIGHT / 64; Format = RGBA16F; }; +texture2D _RenderBloom6 { Width = BUFFER_WIDTH / 64; Height = BUFFER_HEIGHT / 64; Format = RGBA16F; }; sampler2D _SampleBloom6 { Texture = _RenderBloom6; }; texture2D _RenderBloom7 { Width = BUFFER_WIDTH / 128; Height = BUFFER_HEIGHT / 128; Format = RGBA16F; }; diff --git a/shaders/cMosaic.fx b/shaders/cMosaic.fx index d7bd428..fa647a3 100644 --- a/shaders/cMosaic.fx +++ b/shaders/cMosaic.fx @@ -76,7 +76,7 @@ void MosaicPS(float4 Position : SV_POSITION, float2 TexCoord : TEXCOORD0, out fl float2 BlockCoord, MosaicCoord; float MaxRadius = max(_Radius.x, _Radius.y); - [branch] switch(_Shape) + switch(_Shape) { // Circle https://www.shadertoy.com/view/4d2SWy case 0: @@ -92,7 +92,7 @@ void MosaicPS(float4 Position : SV_POSITION, float2 TexCoord : TEXCOORD0, out fl break; // Triangle https://www.shadertoy.com/view/4d2SWy case 1: - const float MaxLODLevel = log2(max(BUFFER_WIDTH, BUFFER_HEIGHT)) - log2(MaxRadius); + const float MaxLODLevel = log2(sqrt((BUFFER_WIDTH * BUFFER_HEIGHT) / (_Radius.x * _Radius.y))); const float2 Divisor = 1.0 / (2.0 * _Radius); BlockCoord = floor(TexCoord * _Radius) / _Radius; TexCoord -= BlockCoord; @@ -100,7 +100,7 @@ void MosaicPS(float4 Position : SV_POSITION, float2 TexCoord : TEXCOORD0, out fl float2 Composite; Composite.x = step(1.0 - TexCoord.y, TexCoord.x); Composite.y = step(TexCoord.x, TexCoord.y); - OutputColor0 = tex2Dlod(_SampleMosaicLOD, float4(BlockCoord + Composite * Divisor, 0.0, MaxLODLevel - 1)); + OutputColor0 = tex2Dlod(_SampleMosaicLOD, float4(BlockCoord + Composite * Divisor, 0.0, MaxLODLevel - 1.0)); break; default: BlockCoord = round(FragCoord / MaxRadius) * MaxRadius; diff --git a/shaders/cMotionBlur.fx b/shaders/cMotionBlur.fx index 34f39b5..e178dce 100644 --- a/shaders/cMotionBlur.fx +++ b/shaders/cMotionBlur.fx @@ -11,7 +11,7 @@ uniform float _Scale < ui_type = "drag"; ui_label = "Flow Scale"; ui_tooltip = "Higher = More motion blur"; -> = 2.0; +> = 4.0; uniform float _Constraint < ui_type = "drag"; @@ -232,8 +232,8 @@ void DerivativesPS(float4 Position : SV_POSITION, float4 Offsets : TEXCOORD0, ou float2 Sample1 = tex2D(_SampleData0, Offsets.xy).xy; // (+x, +y) float2 Sample2 = tex2D(_SampleData0, Offsets.zw).xy; // (-x, -y) float2 Sample3 = tex2D(_SampleData0, Offsets.xw).xy; // (+x, -y) - float2 _ddx = -(Sample2 + Sample0) + (Sample3 + Sample1); - float2 _ddy = -(Sample2 + Sample3) + (Sample0 + Sample1); + float2 _ddx = (-Sample2 + -Sample0) + (Sample3 + Sample1); + float2 _ddy = (Sample2 + Sample3) + (-Sample0 + -Sample1); OutputColor0.x = dot(_ddx, 0.5); OutputColor0.y = dot(_ddy, 0.5); } @@ -268,27 +268,22 @@ void PPVerticalBlurPS(float4 Position : SV_POSITION, float2 TexCoord : TEXCOORD0 OutputColor0 = GaussianBlur(_SampleData0, TexCoord, Offsets).xy; } -float Noise(float2 vpos) -{ - return frac(52.9829189 * frac(dot(vpos.xy, float2(0.06711056, 0.00583715)))); -} - void OutputPS(float4 Position : SV_POSITION, float2 TexCoord : TEXCOORD0, out float4 OutputColor0 : SV_Target) { - float4 Blur; - const float Samples = 1.0 / (8.0 - 1.0); - float2 Flow = tex2Dlod(_SampleData1, float4(TexCoord, 0.0, _Detail)).xy; - Flow = Flow * rcp(_BUFFERSIZE); - Flow *= _Scale; + const int Samples = 4; + float Noise = frac(52.9829189 * frac(dot(Position.xy, float2(0.06711056, 0.00583715)))); + float2 Velocity = tex2Dlod(_SampleData1, float4(TexCoord, 0.0, _Detail)).xy; + float2 TexelSize = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT); + TexCoord *= float2(BUFFER_WIDTH, BUFFER_HEIGHT); - for(int k = 0; k < 9; k++) + for(int k = 0; k < Samples; ++k) { - float2 CalculatePosition = (Noise(Position.xy) + k) * Samples - 0.5; - float4 Color = tex2D(_SampleColor, Flow * CalculatePosition + TexCoord); - Blur = lerp(Blur, Color, rcp(float(k) + 1)); + float2 Offset = Velocity * (Noise + k); + OutputColor0 += tex2D(_SampleColor, (TexCoord + Offset * _Scale) * TexelSize); + OutputColor0 += tex2D(_SampleColor, (TexCoord - Offset * _Scale) * TexelSize); } - OutputColor0 = Blur; + OutputColor0 /= (Samples * 2); } technique cMotionBlur diff --git a/shaders/cPureDepthAO.fx b/shaders/cPureDepthAO.fx new file mode 100644 index 0000000..8be1976 --- /dev/null +++ b/shaders/cPureDepthAO.fx @@ -0,0 +1,250 @@ + +/* + Work In-Progress + Pure Depth Ambient Occlusion + Source http://theorangeduck.com/page/pure-depth-ssao + + Original Port by Jose Negrete AKA BlueSkyDefender + https://github.com/BlueSkyDefender/Depth3D +*/ + +#include "ReShade.fxh" + +uniform float _Strength < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1.0; + ui_label = "Total Strength"; + ui_category = "Ambient Occlusion"; +> = 1.0; + +uniform float _Base < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1.0; + ui_label = "Base Amount"; + ui_category = "Ambient Occlusion"; +> = 0.0; + +uniform float _Area < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1.0; + ui_label = "Area Amount"; + ui_category = "Ambient Occlusion"; +> = 1.0; + +uniform float _Falloff < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1.0; + ui_label = "Falloff Amount"; + ui_category = "Ambient Occlusion"; +> = 0.0; + +uniform float _Radius < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1.0; + ui_label = "Radius Amount"; + ui_category = "Ambient Occlusion"; +> = 0.007; + +uniform float _MipLevel < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1.0; + ui_label = "Occlusion MipMap"; + ui_category = "Ambient Occlusion"; +> = 0.0; + +uniform float _DepthMapAdjust < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1.0; + ui_label = "Depth Map Adjustment"; + ui_tooltip = "This allows for you to adjust the DM precision.\n" + "Adjust this to keep it as low as possible.\n" + "Default is 7.5"; + ui_category = "Depth Buffer"; +> = 0.1; + +uniform int _Debug < + ui_type = "combo"; + ui_items = "Off\0Depth\0AO\0Direction\0"; + ui_label = "Debug View"; + ui_tooltip = "View Debug Buffers."; + ui_category = "Debug Buffer"; +> = 0; + +#define PixelSize float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT) + +texture2D _RenderColor : COLOR; + +sampler2D _SampleColor +{ + Texture = _RenderColor; + SRGBTexture = TRUE; +}; + +texture2D _RenderOcclusion +{ + Width = BUFFER_WIDTH / 2; + Height = BUFFER_HEIGHT / 2; + MipLevels = 9; + Format = R16F; +}; + +sampler2D _SampleOcclusion +{ + Texture = _RenderOcclusion; +}; + +/* [Pixel Shaders] */ + +float2 DepthMap(float2 TexCoord) +{ + float ZBuffer = ReShade::GetLinearizedDepth(TexCoord).x; + ZBuffer /= _DepthMapAdjust; + return float2(ZBuffer, smoothstep(-1.0, 1.0, ZBuffer)); +} + +float4 GetNormal(float2 TexCoord) +{ + const float2 Offset1 = float2(0.0, PixelSize.y); + const float2 Offset2 = float2(PixelSize.x, 0.0); + + float Depth1 = DepthMap(TexCoord + Offset1).x; + float Depth2 = DepthMap(TexCoord + Offset2).x; + + float3 Product1 = float4(Offset1, Depth1 - DepthMap(TexCoord).x); + float3 Product2 = float4(Offset2, Depth2 - DepthMap(TexCoord).x); + + float3 Normal = cross(Product1, Product2); + Normal.z = -Normal.z; + + return normalize(Normal); +} + +void GradientNoise(in float2 Position, in float2 Offset, inout float Noise) +{ + Noise = frac(52.9829189 * frac(dot(Position.xy, float2(0.06711056, 0.00583715) * Offset))); +} + +static const int Samples = 16; + +/* + Stored random vectors inside a sphere unit + TODO: Use Vogel sphere disc for dynamic samples + http://blog.marmakoide.org/?p=1 +*/ + +float3 SphereSamples[Samples] = +{ + float3( 0.5381, 0.1856,-0.4319), + float3( 0.1379, 0.2486, 0.4430), + float3( 0.3371, 0.5679,-0.0057), + float3(-0.6999,-0.0451,-0.0019), + float3( 0.0689,-0.1598,-0.8547), + float3( 0.0560, 0.0069,-0.1843), + float3(-0.0146, 0.1402, 0.0762), + float3( 0.0100,-0.1924,-0.0344), + float3(-0.3577,-0.5301,-0.4358), + float3(-0.3169, 0.1063, 0.0158), + float3( 0.0103,-0.5869, 0.0046), + float3(-0.0897,-0.4940, 0.3287), + float3( 0.7119,-0.0154,-0.0918), + float3(-0.0533, 0.0596,-0.5411), + float3( 0.0352,-0.0631, 0.5460), + float3(-0.4776, 0.2847,-0.0271) +}; + +void OcclusionPS(float4 Position : SV_POSITION, float2 TexCoord : TEXCOORD0, out float4 OutputColor0 : SV_TARGET0) +{ + const int Samples = 16; + float3 Noise; + GradientNoise(TexCoord, float2(1.0, 1.0), Noise.x); + GradientNoise(TexCoord, float2(2.0, 2.0), Noise.y); + GradientNoise(TexCoord, float2(3.0, 3.0), Noise.z); + + // Use Random Noise for Montecarlo + float3 Random = normalize(Noise); + + // Grab Depth Buffer + float Depth = DepthMap(TexCoord).x; + + // Take current texcoords in screen space for sim world position + float3 TexPosition = float3(TexCoord.xy, Depth); + + // Take a normals for reflecting the sample rays in the code below. + float3 Normal = GetNormal(TexCoord); + + // Pre adjustment for Depth sailing that changes the avg radius. + float DepthRadius = _Radius / Depth; + + float4 Occlusion = 0; + + for(int i = 0; i < Samples; i++) + { + // Grabs a vetor from a texture + // Reflect it with in the randomized sphere with radius of 1.0 + float3 Ray = DepthRadius * reflect(SphereSamples[i], Random); // This why the above vetors is sub [-1.0, 1.0] + + // So if the ray is outside the hemisphere then change direction of that ray. + float3 HemiRay = TexPosition + sign(dot(Ray, Normal)) * Ray; + + // Get the depth of the occluder fragment + float OccluderDepth = DepthMap(saturate(HemiRay.xy)).x; + + // So if Difference between Depth is negative then it means the occluder is behind current fragment. + float Difference = Depth - OccluderDepth; + + //Implament your own Z THICCness with area this also is falloff equation + Occlusion += step(_Falloff, Difference) * (1.0 - smoothstep(_Falloff, _Area, Difference)); + + // Can also be done with smoothstep I will add that code later. + } + + float AmbientOcclusion = 1.0 - Occlusion.w * (1.0 / Samples); + + // float3 GlobalIllumination = Occlusion.rgb * (1.0 / Samples); + // return float4(GlobalIllumination, saturate(AmbientOcclusion)); + + OutputColor0 = saturate(AmbientOcclusion + _Base); +} + +void DisplayPS(float4 Position : SV_POSITION, float2 TexCoord : TEXCOORD0, out float3 OutputColor0 : SV_TARGET0) +{ + switch(_Debug) + { + case 0: + OutputColor0 = tex2D(_SampleColor, TexCoord).rgb * tex2Dlod(_SampleOcclusion, float4(TexCoord, 0.0, _MipLevel)).x; + break; + case 1: + OutputColor0 = DepthMap(TexCoord).x; + break; + case 2: + OutputColor0 = tex2Dlod(_SampleOcclusion, float4(TexCoord, 0.0, _MipLevel)); + break; + default: + GetNormal(TexCoord); + break; + } +} + +technique cPureDepthAO +{ + pass AmbientOcclusion + { + VertexShader = PostProcessVS; + PixelShader = OcclusionPS; + RenderTarget0 = _RenderOcclusion; + } + + pass Output + { + VertexShader = PostProcessVS; + PixelShader = DisplayPS; + SRGBWriteEnable = TRUE; + } +} diff --git a/shaders/kDatamosh.fx b/shaders/kDatamosh.fx index b4dba6d..3ccf11f 100644 --- a/shaders/kDatamosh.fx +++ b/shaders/kDatamosh.fx @@ -320,20 +320,20 @@ void AccumulatePS(float4 Position : SV_POSITION, float2 TexCoord : TEXCOORD0, ou Random.z = RandomNoise(TexCoord.yx - Time.xx); // Motion vector - float2 MotionVector = tex2Dlod(_SampleOpticalFlow, float4(TexCoord, 0.0, _Detail)).xy; - MotionVector *= _Scale; + float2 MotionVectors = tex2Dlod(_SampleOpticalFlow, float4(TexCoord, 0.0, _Detail)).xy; + MotionVectors *= _Scale; // Normalized screen space -> Pixel coordinates - MotionVector = MotionVector * _HALFSIZE; + MotionVectors = MotionVectors * _HALFSIZE; // Small random displacement (diffusion) - MotionVector += (Random.xy - 0.5) * _Diffusion; + MotionVectors += (Random.xy - 0.5) * _Diffusion; // Pixel perfect snapping - MotionVector = round(MotionVector); + MotionVectors = round(MotionVectors); // Accumulates the amount of motion. - float MotionVectorLength = length(MotionVector); + float MotionVectorLength = length(MotionVectors); // - Simple update float UpdateAccumulation = min(MotionVectorLength, _BlockSize) * 0.005; @@ -347,7 +347,9 @@ void AccumulatePS(float4 Position : SV_POSITION, float2 TexCoord : TEXCOORD0, ou { OutputColor0.rgb = ResetAccumulation; OutputColor0.a = 0.0; - } else { + } + else + { // This should work given law of addition OutputColor0.rgb = UpdateAccumulation; OutputColor0.a = 1.0; @@ -361,7 +363,28 @@ void OutputPS(float4 Position : SV_POSITION, float2 TexCoord : TEXCOORD0, out fl const float2 DisplacementTexel = 1.0 / _HALFSIZE; const float Quality = 1.0 - _Entropy; + // Random numbers + float2 Time = float2(_Time, 0.0); + float3 Random; + Random.x = RandomNoise(TexCoord.xy + Time.xy); + Random.y = RandomNoise(TexCoord.xy + Time.yx); + Random.z = RandomNoise(TexCoord.yx - Time.xx); + float2 MotionVectors = tex2Dlod(_SampleOpticalFlow, float4(TexCoord, 0.0, _Detail)).xy * DisplacementTexel; + MotionVectors *= _Scale; + + // Normalized screen space -> Pixel coordinates + MotionVectors = MotionVectors * float2(BUFFER_WIDTH, BUFFER_HEIGHT); + + // Small random displacement (diffusion) + MotionVectors += (Random.xy - 0.5) * _Diffusion; + + // Pixel perfect snapping + MotionVectors = round(MotionVectors); + + // Pixel coordinates -> Normalized screen space + MotionVectors *= (float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT) - 1.0); + float4 Source = tex2D(_SampleColor, TexCoord); // Color from the original image float Displacement = tex2D(_SampleAccumulation, TexCoord).r; // Displacement vector float4 Working = tex2D(_SampleFeedback, TexCoord - MotionVectors * 0.98);