mirror of
https://github.com/italicsjenga/slang-shaders.git
synced 2024-11-25 17:01:31 +11:00
282 lines
9.8 KiB
Plaintext
282 lines
9.8 KiB
Plaintext
#version 450
|
|
|
|
layout(push_constant) uniform Push
|
|
{
|
|
vec4 SourceSize;
|
|
vec4 OriginalSize;
|
|
vec4 OutputSize;
|
|
uint FrameCount;
|
|
int FrameDirection;
|
|
} params;
|
|
|
|
#define SamplerColorVHS Original
|
|
|
|
#include "VHSPro_params.inc"
|
|
#include "VHSPro_constants.inc"
|
|
|
|
#pragma stage vertex
|
|
layout(location = 0) in vec4 Position;
|
|
layout(location = 1) in vec2 TexCoord;
|
|
layout(location = 0) out vec2 txcoord;
|
|
|
|
void main()
|
|
{
|
|
gl_Position = global.MVP * Position;
|
|
txcoord = TexCoord;
|
|
}
|
|
|
|
#pragma stage fragment
|
|
layout(location = 0) in vec2 txcoord;
|
|
layout(location = 0) out vec4 FragColor;
|
|
layout(set = 0, binding = 2) uniform sampler2D Original;
|
|
layout(set = 0, binding = 3) uniform sampler2D tape;
|
|
|
|
#include "VHSPro_functions.inc"
|
|
#define SamplerTape tape
|
|
|
|
void main()
|
|
{
|
|
const float t = float(params.FrameCount) * 0.0075;//_Time.y;
|
|
vec2 p = txcoord.xy;
|
|
|
|
float SLN = screenLinesNum; //TODO use only SLN
|
|
float SLN_Noise = noiseLinesNum; //TODO only SLN_Noise
|
|
float ONE_X = 0.0;
|
|
float ONE_Y = 0.0;
|
|
|
|
//basically if its 0 -> set it to fullscreen
|
|
//TODO calc it before shader / already float done
|
|
SLN = screenLinesNum; //TODO use only SLN
|
|
SLN_Noise = noiseLinesNum; //TODO only SLN_Noise
|
|
if(SLN==0.0) SLN = _ScreenParams.y;
|
|
|
|
if(SLN_Noise==0 || SLN_Noise>SLN) SLN_Noise = SLN;
|
|
|
|
ONE_X = 1.0/_ScreenParams.x; //assigning works only here
|
|
ONE_Y = 1.0/_ScreenParams.y;
|
|
|
|
|
|
if (VHS_Twitch_V){
|
|
p = twitchVertical(0.5*twitchVFreq, p, t);
|
|
}
|
|
|
|
if (VHS_Twitch_H){
|
|
p = twitchHorizonal(0.1*twitchHFreq, p, t);
|
|
}
|
|
|
|
//make discrete lines /w or wo float
|
|
if(VHS_LinesFloat){
|
|
float sh = fract(-t*linesFloatSpeed); //shift // float sh = fmod(t, 1.); //shift
|
|
// if(p.x>0.5)
|
|
p.y = -floor( -p.y * SLN + sh )/SLN + sh/SLN; //v1.3
|
|
// p.y = floor( p.y * SLN + sh )/SLN - sh/SLN; //v1.2
|
|
} else {
|
|
// if(p.x>0.5)
|
|
p.y = -floor( -p.y * SLN )/SLN; //v1.3
|
|
// p.y = floor( p.y * SLN )/SLN; //v1.2
|
|
}
|
|
|
|
if (VHS_Stretch){
|
|
p = stretch(p, t, 15.0, 1.0, 0.5, 0.0);
|
|
p = stretch(p, t, 8.0, 1.2, 0.45, 0.5);
|
|
p = stretch(p, t, 11.0, 0.5, -0.35, 0.25); //up
|
|
}
|
|
|
|
if (VHS_Jitter_H){
|
|
if( fmod( p.y * SLN, 2.0)<1.0)
|
|
p.x += ONE_X*sin(t*130.0)*jitterHAmount;
|
|
}
|
|
|
|
//just init
|
|
vec3 col = vec3(0.0,0.0,0.0);
|
|
vec3 signal = vec3(0.0,0.0,0.0);// rgb2yiq(col);
|
|
|
|
//gotta initiate all these things here coz of tape noise distortion
|
|
|
|
//[NOISE uv init]
|
|
//if SLN_Noise different from SLN->recalc linefloat
|
|
vec2 pn = p;
|
|
if(SLN!=SLN_Noise){
|
|
if(VHS_LineNoise){
|
|
const float sh = fract(t); //shift // float sh = fmod(t, 1.); //shift
|
|
pn.y = floor( pn.y * SLN_Noise + sh )/SLN_Noise - sh/SLN_Noise;
|
|
} else {
|
|
pn.y = floor( pn.y * SLN_Noise )/SLN_Noise;
|
|
}
|
|
}
|
|
|
|
//SLN_X is quantization of X. goest from _ScreenParams.x to SLN_X
|
|
const float ScreenLinesNumX = SLN_Noise * _ScreenParams.x / _ScreenParams.y;
|
|
const float SLN_X = noiseQuantizeX*(_ScreenParams.x - ScreenLinesNumX) + ScreenLinesNumX;
|
|
pn.x = floor( pn.x * SLN_X )/SLN_X;
|
|
|
|
const vec2 pn_ = pn*_ScreenParams.xy;
|
|
|
|
//TODO probably it shud be 1.0/SLN_Noise
|
|
const float ONEXN = 1.0/SLN_X;
|
|
//[//noise uv init]
|
|
|
|
float distShift = 0; // for 2nd part of tape noise
|
|
|
|
if (VHS_TapeNoise) {
|
|
|
|
//uv distortion part of tapenoise
|
|
distShift = 0; // for 2nd part of tape noise
|
|
for (int ii = 0; ii < 20 % 1023; ii++){
|
|
|
|
//this is t.n. line value at pn.y and down each pixel
|
|
//TODO i guess ONEXN shud be 1.0/sln noise
|
|
float tnl = textureLod(SamplerTape, vec2(0.0,pn.y-ONEXN*ii), 0.).y;
|
|
// float tnl = texture(SamplerTape, vec2(0.0,pn.y-ONEXN*ii)).y;
|
|
// float tnl = tapeNoiseLines(vec2(0.0,pn.y-ONEXN*i), t*tapeNoiseSpeed)*tapeNoiseAmount;
|
|
tnl -= 0.15 * float(params.FrameDirection);
|
|
// float fadediff = hash12(vec2(pn.x-ONEXN*i,pn.y));
|
|
if(tnl>0.27) {
|
|
//TODO get integer part other way
|
|
const float sh = sin( 1.0*PI*(float(ii)/float(20))) ; //0..1
|
|
p.x -= float(int(sh)*4.0*ONEXN); //displacement
|
|
distShift += sh ; //for 2nd part
|
|
// p.x += ONEXN * float(int(((tnl-thth)/thth)*4.0));
|
|
// col.x = sh;
|
|
}
|
|
}
|
|
}
|
|
|
|
//uv transforms over
|
|
|
|
//picture proccess start
|
|
if (VHS_Jitter_V){
|
|
signal = yiqDist(p, jitterVAmount, t*jitterVSpeed);
|
|
} else {
|
|
col = texture(SamplerColorVHS, p).rgb;
|
|
// col = vec3(p.xy, 0.0);//debug
|
|
signal = rgb2yiq(col);
|
|
}
|
|
|
|
|
|
if (VHS_LineNoise || VHS_FilmGrain){
|
|
signal.x += texture(SamplerTape, pn).z;
|
|
}
|
|
|
|
//iq noise from yiq
|
|
if (VHS_YIQNoise){
|
|
if (signalNoiseType == 0) {
|
|
//TODO make cheaper noise
|
|
//type 1 (best) w Y mask
|
|
const vec2 noise = n4rand_bw( pn_,t,1.0-signalNoisePower ) ;
|
|
signal.y += (noise.x*2.0-1.0)*signalNoiseAmount*signal.x;
|
|
signal.z += (noise.y*2.0-1.0)*signalNoiseAmount*signal.x;
|
|
} else if (signalNoiseType == 1){
|
|
//type 2
|
|
const vec2 noise = n4rand_bw( pn_,t, 1.0-signalNoisePower ) ;
|
|
signal.y += (noise.x*2.0-1.0)*signalNoiseAmount;
|
|
signal.z += (noise.y*2.0-1.0)*signalNoiseAmount;
|
|
} else {
|
|
//type 3
|
|
const vec2 noise = n4rand_bw( pn_,t, 1.0-signalNoisePower )*signalNoiseAmount ;
|
|
signal.y *= noise.x;
|
|
signal.z *= noise.y;
|
|
signal.x += (noise.x*2.0-1.0)*0.05;
|
|
}
|
|
}
|
|
|
|
//2nd part with noise, tail and yiq col shift
|
|
if (VHS_TapeNoise){
|
|
|
|
//here is normilized p (0..1)
|
|
float tn = texture(SamplerTape, pn).x;
|
|
signal.x = bms(signal.x, tn*tapeNoiseAmount ).x;
|
|
// float tn = tapeNoise(pn, t*tapeNoiseSpeed)*tapeNoiseAmount;
|
|
|
|
//tape noise tail
|
|
const int tailLength=10; //TODO adjustable
|
|
|
|
for(int j = 0; j < tailLength % 1023; j++){
|
|
|
|
const float jj = float(j);
|
|
const vec2 d = vec2(pn.x-ONEXN*jj,pn.y);
|
|
tn = textureLod(SamplerTape, vec2(d), 0. ).x;
|
|
// tn = texture(SamplerTape, d).x;
|
|
// tn = tapeNoise(vec2(pn.x-ONEXN*i,pn.y), t*tapeNoiseSpeed)*tapeNoiseAmount;
|
|
|
|
float fadediff = 0.0;
|
|
|
|
//for tails length difference
|
|
// if(__RENDERER__ == 0x0A100 || __RENDERER__ == 0x0B000) {
|
|
// fadediff = textureLod(SamplerTape, vec2(d), 0.).a; //hash12(d);
|
|
// }
|
|
|
|
// if(__RENDERER__ == 0x09300 || __RENDERER__ >= 0x10000) {
|
|
fadediff = texture(SamplerTape, d).a; //hash12(d);
|
|
// }
|
|
|
|
if( tn > 0.8 ){
|
|
float nsx = 0.0; //new signal x
|
|
const float newlength = float(tailLength)*(1.0-fadediff); //tail lenght diff
|
|
if( jj <= newlength ) nsx = 1.0-( jj/ newlength ); //tail
|
|
signal.x = bms(signal.x, nsx*tapeNoiseAmount).x;
|
|
}
|
|
}
|
|
|
|
//tape noise color shift
|
|
if(distShift>0.4){
|
|
// float tnl = tapeNoiseLines(vec2(0.0,pn.y), t*tapeNoiseSpeed)*tapeNoiseAmount;
|
|
const float tnl = texture(SamplerTape, pn).y;//tapeNoiseLines(vec2(0.0,pn.y), t*tapeNoiseSpeed)*tapeNoiseAmount;
|
|
signal.y *= 1.0/distShift;//tnl*0.1;//*distShift;//*signal.x;
|
|
signal.z *= 1.0/distShift;//*distShift;//*signal.x;
|
|
|
|
}
|
|
}
|
|
|
|
//back to rgb color space
|
|
//signal has negative values
|
|
col = yiq2rgb(signal);
|
|
|
|
//TODO put it into 2nd pass
|
|
if (VHS_ScanLines){
|
|
col *= scanLines(txcoord.xy, t);
|
|
}
|
|
|
|
//fisheye cutoff / outside fisheye
|
|
//helps to remove noise outside the fisheye
|
|
if (VHS_FishEye){
|
|
|
|
p = txcoord.xy;
|
|
|
|
float far;
|
|
const vec2 hco = vec2(ONE_X*cutoffX, ONE_Y*cutoffY) * 0.25; //hard cuttoff x
|
|
const vec2 sco = vec2(ONE_X*cutoffFadeX, ONE_Y*cutoffFadeY) * 0.25; //soft cuttoff x
|
|
|
|
//hard cutoff
|
|
if( p.x<=(0.0+hco.x) || p.x>=(1.0-hco.x) || p.y<=(0.0+hco.y) || p.y>=(1.0-hco.y) ){
|
|
col = vec3(0.0,0.0,0.0);
|
|
} else {
|
|
//fades
|
|
|
|
if( //X
|
|
(p.x>(0.0+hco.x) && p.x<(0.0+(sco.x+hco.x) )) || (p.x>(1.0-(sco.x+hco.x)) && p.x<(1.0-hco.x))
|
|
){
|
|
if(p.x<0.5) far = (0.0-hco.x+p.x)/(sco.x);
|
|
else
|
|
far = (1.0-hco.x-p.x)/(sco.x);
|
|
|
|
col *= float(far).xxx;
|
|
};
|
|
|
|
if( //Y
|
|
(p.y>(0.0+hco.y) && p.y<(0.0+(sco.y+hco.y) )) || (p.y>(1.0-(sco.y+hco.y)) && p.y<(1.0-hco.y))
|
|
){
|
|
if(p.y<0.5) far = (0.0-hco.y+p.y)/(sco.y);
|
|
else
|
|
far = (1.0-hco.y-p.y)/(sco.y);
|
|
|
|
col *= float(far).xxx;
|
|
}
|
|
}
|
|
}
|
|
|
|
// col = texture(SamplerTape, txcoord.xy).x;
|
|
|
|
FragColor = vec4(col, 1.0);
|
|
// FragColor = (VHS_TapeNoise && params.FrameDirection < 0) ? FragColor + (vec4(texture(tape, txcoord).g)) * 2. : FragColor;
|
|
} |