Annotations
This commit is contained in:
@@ -8,6 +8,8 @@ float2 jumpy(float2 uv, float framecount)
|
||||
float2 look = uv;
|
||||
float m = frac(framecount / 4.0);
|
||||
float dy = look.y - m;
|
||||
// Localize the horizontal tear to a moving scanline window instead of
|
||||
// bending the whole frame equally.
|
||||
float window = 1.0 / (1.0 + 80.0 * dy * dy);
|
||||
look.x += 0.05 * sin(look.y * 10.0 + framecount) / 20.0 * onOff(4.0, 4.0, 0.3, framecount) * (0.5 + cos(framecount * 20.0)) * window;
|
||||
float vShift = (0.1 * wiggle) * 0.4 * onOff(2.0, 3.0, 0.9, framecount) * (sin(framecount) * sin(framecount * 20.0) + (0.5 + 0.1 * sin(framecount * 200.0) * cos(framecount)));
|
||||
@@ -59,6 +61,8 @@ float grainScalar(float2 uv)
|
||||
float3 animatedChromaGrain(float2 uv, float time, float2 outputResolution, float grainSize)
|
||||
{
|
||||
float safeGrainSize = max(grainSize, 0.001);
|
||||
// Quantize the coordinates first so larger grain sizes become visible
|
||||
// chroma blocks rather than simply lower-frequency smooth noise.
|
||||
float2 baseUv = uv * outputResolution * float2(0.85, 0.95) / safeGrainSize;
|
||||
float2 grainUv = floor(baseUv) + 0.5;
|
||||
float2 drift = float2(time * 19.7, time * 23.3);
|
||||
@@ -87,6 +91,8 @@ float valueNoise2(float2 p)
|
||||
float tapeLineNoise(float2 uv, float time, float2 outputResolution)
|
||||
{
|
||||
float y = floor(uv.y * outputResolution.y);
|
||||
// Combine stable per-line noise with frame-rate noise so bands have both
|
||||
// slow tape wander and fast electronic shimmer.
|
||||
float slowLine = valueNoise2(float2(y * 0.021, floor(time * 10.0)));
|
||||
float fastLine = noiseHash(float2(y * 1.73, floor(time * 59.94)));
|
||||
float line = (slowLine * 0.7 + fastLine * 0.3) * 2.0 - 1.0;
|
||||
@@ -102,6 +108,8 @@ float3 analogStatic(float2 uv, float time, float2 outputResolution)
|
||||
float frame = floor(time * 59.94);
|
||||
float seed = frac(time);
|
||||
|
||||
// Several differently skewed hashes keep the snow from forming obvious
|
||||
// diagonal or grid patterns at broadcast frame cadence.
|
||||
float2 goldPixel = pixel + float2(0.37, 0.61) + frame;
|
||||
float snowA = goldNoise(goldPixel, seed + 0.1);
|
||||
float snowB = goldNoise(goldPixel * float2(0.37, 2.11) + float2(19.0, 41.0), seed + 0.2);
|
||||
@@ -146,6 +154,8 @@ float3 blurVhs(float2 uv, float d, int sampleCount)
|
||||
float2 pixelOffset = float2(d, 0.0);
|
||||
float2 scale = 0.66 * 8.0 * pixelOffset;
|
||||
|
||||
// The circular tap pattern approximates soft tape smear while keeping the
|
||||
// maximum loop bound fixed for shader compilation.
|
||||
for (int i = 0; i < 15; ++i)
|
||||
{
|
||||
if (i >= sampleCount)
|
||||
@@ -170,6 +180,8 @@ float4 buildTapeSmear(ShaderContext context)
|
||||
float framecount = frac(time * wiggleSpeed / 7.0) * 7.0;
|
||||
int sampleCount = int(clamp(blurSamples, 3.0, 15.0) + 0.5);
|
||||
|
||||
// Split the source into YIQ, smear each component by a different amount,
|
||||
// then recombine to mimic luma/chroma bandwidth mismatch on tape.
|
||||
float d = 0.1 - round(frac(time / 3.0)) * 0.1;
|
||||
uv = jumpy(uv, framecount);
|
||||
float s = 0.0001 * -d + 0.0001 * wiggle * sin(time * wiggleSpeed);
|
||||
@@ -202,6 +214,8 @@ float4 finishVhs(ShaderContext context)
|
||||
float time = distortedTapeTime(context);
|
||||
float3 color = sampleVideo(context.uv).rgb;
|
||||
|
||||
// Radial red/blue offsets create lens and deck misregistration before the
|
||||
// wider tape effects are layered in.
|
||||
float2 centered = context.uv * 2.0 - 1.0;
|
||||
centered.x *= context.outputResolution.x / max(context.outputResolution.y, 1.0);
|
||||
float2 aberrationOffset = centered * (aberrationAmount * 0.0015);
|
||||
@@ -219,6 +233,8 @@ float4 finishVhs(ShaderContext context)
|
||||
float halationMask = smoothstep(0.45, 1.0, halationLuma) * halationAmount;
|
||||
color += halationSource * float3(1.0, 0.38, 0.24) * halationMask * 0.35;
|
||||
|
||||
// Bloom and fade are applied as separate layers so highlights glow without
|
||||
// flattening the full picture into the faded black level.
|
||||
float3 bloomSource = softBloom(context.uv, context.outputResolution, 2.0 + smear * 2.5);
|
||||
float bloomLuma = dot(bloomSource, float3(0.299, 0.587, 0.114));
|
||||
float bloomMask = smoothstep(0.32, 1.0, bloomLuma) * bloomAmount;
|
||||
@@ -229,6 +245,8 @@ float4 finishVhs(ShaderContext context)
|
||||
float luma = dot(color, float3(0.299, 0.587, 0.114));
|
||||
float noiseMask = lerp(0.65, 1.0, 1.0 - saturate(luma));
|
||||
float chunkiness = lerp(1.0, 2.4, saturate((noiseSize - 1.0) / 5.0));
|
||||
// Push darker regions harder: analog noise reads most naturally in shadows
|
||||
// and avoids washing out bright highlights.
|
||||
float3 chromaNoise = float3(speckle.x * 1.2, speckle.y * 0.28, speckle.z * 1.35);
|
||||
color += chromaNoise * noiseAmount * noiseMask * chunkiness;
|
||||
color.rg = lerp(color.rg, float2(color.r, color.g) + speckle.xy * noiseAmount * 0.2 * chunkiness, 0.35);
|
||||
|
||||
Reference in New Issue
Block a user