Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Working analog glitch effect. #40

Merged
merged 1 commit into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ target_sources(${PROJECT_NAME} PRIVATE
src/blur/blur.h
src/blur/gaussian-kernel.c
src/blur/gaussian-kernel.h
src/filters/analog-glitch.c
src/filters/analog-glitch.h
src/filters/bloom-f.c
src/filters/bloom-f.h
src/filters/cathode-boot.c
Expand Down
19 changes: 19 additions & 0 deletions data/locale/en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,22 @@ RetroEffects.DigitalGlitch.MinRGBHeight="Min Height"
RetroEffects.DigitalGlitch.MaxRGBHeight="Max Height"
RetroEffects.DigitalGlitch.MinRGBInterval="Min Interval"
RetroEffects.DigitalGlitch.MaxRGBInterval="Max Interval"
RetroEffects.AnalogGlitch="Analog Glitch"
RetroEffects.AnalogGlitch.Primary="Primary Wave"
RetroEffects.AnalogGlitch.Primary.Speed="Speed"
RetroEffects.AnalogGlitch.Primary.Scale="Scale"
RetroEffects.AnalogGlitch.Primary.Threshold="Threshold"
RetroEffects.AnalogGlitch.Secondary="Secondary Wave"
RetroEffects.AnalogGlitch.Secondary.Speed="Speed"
RetroEffects.AnalogGlitch.Secondary.Scale="Scale"
RetroEffects.AnalogGlitch.Secondary.Threshold="Threshold"
RetroEffects.AnalogGlitch.Secondary.Influence="Influence"
RetroEffects.AnalogGlitch.MaximumDisplacement="Max Displacement"
RetroEffects.AnalogGlitch.Interference="Interference"
RetroEffects.AnalogGlitch.Interference.Magnitude="Interference Magnitude"
RetroEffects.AnalogGlitch.Interference.AffectsAlpha="Alpha Channel?"
RetroEffects.AnalogGlitch.Line.Magnitude="Line Magnitude"
RetroEffects.AnalogGlitch.CA="Color Drift"
RetroEffects.AnalogGlitch.CA.MaxDisp="Maximum Distance"
RetroEffects.AnalogGlitch.DeSat="Desaturation"
RetroEffects.AnalogGlitch.DeSat.Amount="Amount"
104 changes: 104 additions & 0 deletions data/shaders/analog-glitch.effect
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Based off of ShaderToy "Video Glitch" by dyvoid.
// https://www.shadertoy.com/view/XtK3W3
// Converted to HLSL, added user changable parameters,
// And added CA effect by Finite Singularity.

uniform float4x4 ViewProj;
uniform texture2d image;
uniform float2 uv_size;
uniform float time;

uniform float speed_primary; //= 2.0;
uniform float speed_secondary; // = 5.0;
uniform float scale_primary; // = 800.0;
uniform float scale_secondary; // = 128.0;

uniform float threshold_primary; // = 0.3;
uniform float threshold_secondary; // = 0.7;
uniform float secondary_influence; // = 0.15;

uniform float max_disp; // = 250.0;
uniform float interference_mag; // = 0.3;
uniform float line_mag; // = 0.15;
uniform float interference_alpha;

uniform float desaturation_amount;
uniform float color_drift;

#include "noise-functions.effect"

sampler_state textureSampler{
Filter = Linear;
AddressU = Clamp;
AddressV = Clamp;
MinLOD = 0;
MaxLOD = 0;
};

struct VertData
{
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};

VertData mainTransform(VertData v_in)
{
v_in.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj);
return v_in;
}

// Sample with desaturation
float4 sampleDesaturatedTexture(float2 xy, float desat)
{
// Desaturation Distortion
float4 col = image.Sample(textureSampler, xy / uv_size);
float lum = dot(col.rgb, float3(0.299, 0.587, 0.114));
col.rgb = lerp(col.rgb, float3(lum, lum, lum), float3(desat, desat, desat));
return col;
}

float4 mainImage(VertData v_in) : TARGET
{
float2 coord = v_in.uv * uv_size;

float n_primary = open_simplex_1d(float2(time * speed_primary, coord.y), 0.0, float2(1.0, scale_primary));
float n_secondary = open_simplex_1d(float2(time * speed_secondary, coord.y), 0.0, float2(1.0, scale_secondary));

n_primary = max(0.0, (n_primary - threshold_primary)) / (1.0 - threshold_primary);
n_primary += n_secondary * secondary_influence;
n_primary /= (1.0 + secondary_influence);

coord.x = coord.x - max_disp * n_primary * n_primary;

// CA Distortion and Desaturation
float desat = n_primary * desaturation_amount;
float4 col_g = sampleDesaturatedTexture(coord, desat);
float4 col_r = sampleDesaturatedTexture(coord - float2(n_primary * color_drift, 0.0), desat);
float4 col_b = sampleDesaturatedTexture(coord + float2(n_primary * color_drift, 0.0), desat);

float4 col = float4(col_r.r, col_g.g, col_b.b, (col_r.a + col_g.a + col_b.a)*0.33334);

// Interference noise (lightening/darkening)
float n_interference = hash11(coord.y * time*5.0);
float inter = n_primary * interference_mag;
col.rgb = lerp(col.rgb, float3(n_interference, n_interference, n_interference), float3(inter, inter, inter));

// Static lines (correlated to primary displacement)
if (floor(fmod(coord.y * 0.25, 2.0)) < 0.001)
{
float intf = 1.0 - (line_mag * n_primary);
col.rgb *= intf;
col.a = col.a - (interference_alpha * (1.0 - intf));
}

return col;
}

technique Draw
{
pass
{
vertex_shader = mainTransform(v_in);
pixel_shader = mainImage(v_in);
}
}
161 changes: 161 additions & 0 deletions data/shaders/noise-functions.effect
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,164 @@ float2 whiteNoise2D(float2 pos, uint seed)
);
#endif
}

////////////////// K.jpg's Smooth Re-oriented 8-Point BCC Noise //////////////////
//////////////////// Output: float4(dF/dx, dF/dy, dF/dz, value) ////////////////////

// Borrowed from Stefan Gustavson's noise code

float4 permute(float4 t)
{
return t * (t * 34.0 + 133.0);
}

#ifndef OPENGL
float mod(float x, float y)
{
return x - y * floor(x / y);
}

float2 mod(float2 x, float2 y)
{
return x - y * floor(x / y);
}

float3 mod(float3 x, float3 y)
{
return x - y * floor(x / y);
}

float4 mod4(float4 x, float4 y)
{
return x - y * floor(x / y);
}
#endif

// Gradient set is a normalized expanded rhombic dodecahedron
float3 grad(float hash)
{
// Random vertex of a cube, +/- 1 each
float3 cube = mod(floor(hash / float3(1.0, 2.0, 4.0)), 2.0) * 2.0 - 1.0;

// Random edge of the three edges connected to that vertex
// Also a cuboctahedral vertex
// And corresponds to the face of its dual, the rhombic dodecahedron
float3 cuboct = cube;

int index = int(hash / 16.0);
if (index == 0)
cuboct.x = 0.0;
else if (index == 1)
cuboct.y = 0.0;
else
cuboct.z = 0.0;

// In a funky way, pick one of the four points on the rhombic face
float type = mod(floor(hash / 8.0), 2.0);
float3 rhomb = (1.0 - type) * cube + type * (cuboct + cross(cube, cuboct));

// Expand it so that the new edges are the same length
// as the existing ones
float3 grad = cuboct * 1.22474487139 + rhomb;

// To make all gradients the same length, we only need to shorten the
// second type of vector. We also put in the whole noise scale constant.
// The compiler should reduce it into the existing floats. I think.
grad *= (1.0 - 0.042942436724648037 * type) * 3.5946317686139184;

return grad;
}

// BCC lattice split up into 2 cube lattices
float4 openSimplex2SDerivativesPart(float3 X)
{
float3 b = floor(X);
float4 i4 = float4(X - b, 2.5);

// Pick between each pair of oppposite corners in the cube.
float3 v1 = b + floor(dot(i4, float4(.25, .25, .25, .25)));
float3 v2 = b + float3(1, 0, 0) + float3(-1, 1, 1) * floor(dot(i4, float4(-.25, .25, .25, .35)));
float3 v3 = b + float3(0, 1, 0) + float3(1, -1, 1) * floor(dot(i4, float4(.25, -.25, .25, .35)));
float3 v4 = b + float3(0, 0, 1) + float3(1, 1, -1) * floor(dot(i4, float4(.25, .25, -.25, .35)));

// Gradient hashes for the four vertices in this half-lattice.
float4 hashes = float4(
hash33(v1).x, hash33(v2).x, hash33(v3).x, hash33(v4).x
) * 47.0;


// Gradient extrapolations & kernel function
float3 d1 = X - v1;
float3 d2 = X - v2;
float3 d3 = X - v3;
float3 d4 = X - v4;
float4 a = max(float4(0.75, 0.75, 0.75, 0.75) - float4(dot(d1, d1), dot(d2, d2), dot(d3, d3), dot(d4, d4)), float4(0.0, 0.0, 0.0, 0.0));
float4 aa = a * a;
float4 aaaa = aa * aa;
float3 g1 = grad(hashes.x);
float3 g2 = grad(hashes.y);
float3 g3 = grad(hashes.z);
float3 g4 = grad(hashes.w);
float4 extrapolations = float4(dot(d1, g1), dot(d2, g2), dot(d3, g3), dot(d4, g4));

#ifndef OPENGL
float4x3 derivativeMatrix = { d1, d2, d3, d4 };
float4x3 gradientMatrix = { g1, g2, g3, g4 };

// Derivatives of the noise
float3 derivative = -8.0 * mul(aa * a * extrapolations, derivativeMatrix)
+ mul(aaaa, gradientMatrix);

#else
vec3 derivative = -8.0 * mat4x3(d1, d2, d3, d4) * (aa * a * extrapolations) + mat4x3(g1, g2, g3, g4) * aaaa;
#endif

// Return it all as a float4
return float4(derivative, dot(aaaa, extrapolations));
}

// Use this if you don't want Z to look different from X and Y
float4 openSimplex2SDerivatives_Conventional(float3 X)
{
X = dot(X, float3(2.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0)) - X;

float4 result = openSimplex2SDerivativesPart(X) + openSimplex2SDerivativesPart(X + 144.5);

return float4(dot(result.xyz, float3(2.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0)) - result.xyz, result.w);
}

// Use this if you want to show X and Y in a plane, then use Z for time, vertical, etc.
float4 openSimplex2SDerivatives_ImproveXY(float3 X)
{
#ifndef OPENGL
// Not a skew transform.
float3x3 orthonormalMap =
{
0.788675134594813, -0.211324865405187, -0.577350269189626,
-0.211324865405187, 0.788675134594813, -0.577350269189626,
0.577350269189626, 0.577350269189626, 0.577350269189626
};

X = mul(X, orthonormalMap);
float4 result = openSimplex2SDerivativesPart(X) + openSimplex2SDerivativesPart(X + 144.5);
return float4(mul(orthonormalMap, result.xyz), result.w);
#else
mat3 orthonormalMap = mat3(
0.788675134594813, -0.211324865405187, -0.577350269189626,
-0.211324865405187, 0.788675134594813, -0.577350269189626,
0.577350269189626, 0.577350269189626, 0.577350269189626);

X = orthonormalMap * X;
float4 result = openSimplex2SDerivativesPart(X) + openSimplex2SDerivativesPart(X + 144.5);

return vec4(result.xyz * orthonormalMap, result.w);
#endif
}

float open_simplex_1d(float2 coord, float t, float2 scale)
{
coord *= 1.0 / (scale);
float4 noise = openSimplex2SDerivatives_Conventional(float3(coord, t));
return noise.w;
//return noise.w * 0.5 + 0.5;
}
Loading
Loading