slang-shaders/vhs/shaders/VHSPro/VHSPro_functions.inc
2020-06-19 16:19:28 -05:00

361 lines
12 KiB
C++

//functions
#define PI 3.14159265359
const vec3 MOD3 = vec3(443.8975, 397.2973, 491.1871);
float fmod(float a, float b) {
const float c = fract(abs(a / b)) * abs(b);
if (a < 0)
return -c;
else
return c;
}
vec3 bms(vec3 c1, vec3 c2){ return 1.0- (1.0-c1)*(1.0-c2); }
float bms(float c1, float c2){ return 1.0- (1.0-c1)*(1.0-c2); }
//turns sth on and off //a - how often
float onOff(float a, float b, float c, float t)
{
return step(c, sin(t + a*cos(t*b)));
}
float hash( float n ){ return fract(sin(n)*43758.5453123); }
float hash12(vec2 p){
vec3 p3 = fract(vec3(p.xyx) * MOD3);
p3 += dot(p3, p3.yzx + 19.19);
return fract(p3.x * p3.z * p3.y);
}
vec2 hash22(vec2 p) {
vec3 p3 = fract(vec3(p.xyx) * MOD3);
p3 += dot(p3.zxy, p3.yzx+19.19);
return fract(vec2((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y));
}
//random hash
vec4 hash42(vec2 p)
{
vec4 p4 = fract(vec4(p.xyxy) * vec4(443.8975,397.2973, 491.1871, 470.7827));
p4 += dot(p4.wzxy, p4 + 19.19);
return fract(vec4(p4.x * p4.y, p4.x*p4.z, p4.y*p4.w, p4.x*p4.w));
}
float niq( in vec3 x ){
const vec3 p = floor(x);
vec3 f = fract(x);
f = f*f*(3.0-2.0*f);
const float n = p.x + p.y*57.0 + 113.0*p.z;
return mix(mix( mix( hash(n+ 0.0), hash(n+ 1.0),f.x),
mix( hash(n+ 57.0), hash(n+ 58.0),f.x),f.y),
mix( mix( hash(n+113.0), hash(n+114.0),f.x),
mix( hash(n+170.0), hash(n+171.0),f.x),f.y),f.z);
}
float filmGrain(vec2 uv, float t, float c )
{
//cheap noise - is ok atm
return pow(hash12( uv + 0.07*fract( t ) ), 3);
}
vec2 n4rand_bw( vec2 p, float t, float c )
{
t = fract( t );//that's why its sort of twitching
vec2 nrnd0 = hash22( p + 0.07*t );
c = 1.0 / (10.0*c); //iMouse.y / iResolution.y
return pow(nrnd0, vec2(c,c)); //TODO try to invert 1-...
}
float scanLines(vec2 p, float t)
{
//cheap (maybe make an option later)
// float scanLineWidth = 0.26;
// float scans = 0.5*(cos((p.y*screenLinesNum+t+.5)*2.0*PI) + 1.0);
// if(scans>scanLineWidth) scans = 1.; else scans = 0.;
float t_sl = 0.0;
//if lines aren't floating -> scanlines also shudn't
if (VHS_LinesFloat) {
t_sl = t*linesFloatSpeed;
}
//expensive but better
float scans = 0.5*(cos( (p.y*(screenLinesNum * 0.5)+t_sl)*2.0*PI) + 1.0);
scans = pow(scans, scanLineWidth);
return 1.0 - scans;
}
float gcos(vec2 uv, float s, float p)
{
return (cos( uv.y * PI * 2.0 * s + p)+1.0)*0.5;
}
//mw - maximum width
//wcs = widthChangeSpeed
//lfs = line float speed = .5
//lf phase = line float phase = .0
vec2 stretch(vec2 uv, float t, float mw, float wcs, float lfs, float lfp){
const float SLN = screenLinesNum; //TODO use only SLN
//width change
const float tt = t*wcs; //widthChangeSpeed
const float t2 = tt-fmod(tt, 0.5);
//float dw = hash42( vec2(0.01, t2) ).x ; //on t and not on y
float w = gcos(uv, 2.0*(1.0-fract(t2)), PI-t2) * clamp( gcos(uv, fract(t2), t2) , 0.5, 1.0);
//w = clamp(w,0.,1.);
w = floor(w*mw)/mw;
w *= mw;
//get descreete line number
float ln = (1.0-fract(t*lfs + lfp)) *screenLinesNum;
ln = ln - fract(ln);
// float ln = (1.-fmod(t*lfs + lfp, 1.))*SLN;
// ln = ln - fmod(ln, 1.); //descreete line number
//ln = 10.;
//w = 4.;
//////stretching part///////
const float oy = 1.0/SLN; //TODO global
const float sh2 = 1.0 - fmod(ln, w)/w; // shift 0..1
// #if VHS_LINESFLOAT_ON
// float sh = fmod(t, 1.);
// uv.y = floor( uv.y *SLN +sh )/SLN - sh/SLN;
// #else
// uv.y = floor( uv.y *SLN )/SLN;
// #endif
// uv.y = floor( uv.y *SLN )/SLN ;
const float slb = SLN / w; //screen lines big
//TODO finish
// #if VHS_LINESFLOAT_ON
// if(uv.y<oy*ln && uv.y>oy*(ln-w)) ////if(uv.y>oy*ln && uv.y<oy*(ln+w))
// uv.y = floor( uv.y*slb +sh2 +sh )/slb - (sh2-1.)/slb - sh/slb;
// #else
if(uv.y<oy*ln && uv.y>oy*(ln-w)) ////if(uv.y>oy*ln && uv.y<oy*(ln+w))
uv.y = floor( uv.y*slb +sh2 )/slb - (sh2-1.0)/slb ;
// #endif
return uv;
}
float rnd_rd(vec2 co)
{
return fract(sin(fmod(dot(co.xy ,vec2(12.9898,78.233)),3.14)) * 43758.5453);
}
//DANG WINDOWS
vec3 rgb2yiq(vec3 c)
{
return vec3(
0.2989*c.x + 0.5959*c.y + 0.2115*c.z,
0.5870*c.x - 0.2744*c.y - 0.5229*c.z,
0.1140*c.x - 0.3216*c.y + 0.3114*c.z);
}
vec3 yiq2rgb(vec3 c)
{
return vec3(
1.0*c.x +1.0*c.y +1.0*c.z,
0.956*c.x - 0.2720*c.y - 1.1060*c.z,
0.6210*c.x - 0.6474*c.y + 1.7046*c.z);
}
//rgb distortion
vec3 rgbDistortion(vec2 uv, float magnitude, float t)
{
magnitude *= 0.0001; // float magnitude = 0.0009;
vec3 offsetX = vec3( uv.x, uv.x, uv.x );
offsetX.r += rnd_rd(vec2(t*0.03,uv.y*0.42)) * 0.001 + sin(rnd_rd(vec2(t*0.2, uv.y)))*magnitude;
offsetX.g += rnd_rd(vec2(t*0.004,uv.y*0.002)) * 0.004 + sin(t*9.0)*magnitude;
// offsetX.b = uv.y + rnd_rd(vec2(cos(t*0.01),sin(uv.y)))*magnitude;
// offsetX.b = uv.y + rand_rd(vec2(cos(t*0.01),sin(uv.y)))*magnitude;
vec3 col = vec3(0.0, 0.0, 0.0);
//it cud be optimized / but hm
col.x = rgb2yiq( texture( SamplerColorVHS, vec2(offsetX.r, uv.y) ).rgb ).x;
col.y = rgb2yiq( texture( SamplerColorVHS, vec2(offsetX.g, uv.y) ).rgb ).y;
col.z = rgb2yiq( texture( SamplerColorVHS, vec2(offsetX.b, uv.y) ).rgb ).z;
col = yiq2rgb(col);
return col;
}
float rndln(vec2 p, float t)
{
float sample_ln = rnd_rd(vec2(1.0,2.0*cos(t))*t*8.0 + p*1.0).x;
sample_ln *= sample_ln;//*sample;
return sample_ln;
}
float lineNoise(vec2 p, float t)
{
float n = rndln(p* vec2(0.5,1.0) + vec2(1.0,3.0), t)*20.0;
float freq = abs(sin(t)); //1.
float c = n*smoothstep(fmod(p.y*4.0 + t/2.0+sin(t + sin(t*0.63)),freq), 0.0,0.95);
return c;
}
// 3d noise function (iq's)
float n( in vec3 x )
{
const vec3 p = floor(x);
vec3 f = fract(x);
f = f*f*(3.0-2.0*f);
const float n = p.x + p.y*57.0 + 113.0*p.z;
return mix(mix(mix( hash(n+0.0), hash(n+1.0),f.x),
mix( hash(n+ 57.0), hash(n+ 58.0),f.x),f.y),
mix( mix( hash(n+113.0), hash(n+114.0),f.x),
mix( hash(n+170.0), hash(n+171.0),f.x),f.y),f.z);
}
float tapeNoiseLines(vec2 p, float t){
//so atm line noise is depending on hash for int values
//i gotta rewrite to for hash for 0..1 values
//then i can use normilized p for generating lines
const float y = p.y*_ScreenParams.y;
const float s = t*2.0;
return (niq( vec3(y*0.01 +s, 1.0, 1.0) ) + 0.0)
*(niq( vec3(y*0.011+1000.0+s, 1.0, 1.0) ) + 0.0)
*(niq( vec3(y*0.51+421.0+s, 1.0, 1.0) ) + 0.0)
;
}
float tapeNoise(float nl, vec2 p, float t){
//TODO custom adjustable density (Probability distribution)
// but will be expensive (atm its ok)
//atm its just contrast noise
//this generates noise mask
float nm = hash12( fract(p+t*vec2(0.234,0.637)) )
// *hash12( fract(p+t*vec2(0.123,0.867)) )
// *hash12( fract(p+t*vec2(0.441,0.23)) );
;
nm = pow(nm, 4) +0.3; //cheap and ok
//nm += 0.3 ; //just bit brighter or just more to threshold?
nl*= nm; // put mask
// nl += 0.3; //Value add .3//
if(nl<tapeNoiseTH) nl = 0.0; else nl =1.0; //threshold
return nl;
}
vec2 twitchVertical(float freq, vec2 uv, float t){
float vShift = 0.4*onOff(freq,3.0,0.9, t);
vShift*=(sin(t)*sin(t*20.0) + (0.5 + 0.1*sin(t*200.0)*cos(t)));
uv.y = fmod(uv.y + vShift, 1.0);
return uv;
}
vec2 twitchHorizonal(float freq, vec2 uv, float t){
uv.x += sin(uv.y*10.0 + t)/250.0*onOff(freq,4.0,0.3, t)*(1.0+cos(t*80.0))*(1.0/(1.0+20.0*(uv.y-fmod(t/4.0,1.0))*(uv.y-fmod(t/4.0, 1.0))));
return uv;
}
//all that shit is for postVHS"Pro"_First - end
//all that shit is for postVHS"Pro"_Second
//size 1.2, bend 2.
vec2 fishEye(vec2 uv, float size, float bend)
{
if (!VHS_FishEye_Hyperspace){
uv -= vec2(0.5,0.5);
uv *= size*(1.0/size+bend*uv.x*uv.x*uv.y*uv.y);
uv += vec2(0.5,0.5);
}
if (VHS_FishEye_Hyperspace){
//http://paulbourke.net/miscellaneous/lenscorrection/
const float prop = _ScreenParams.x / _ScreenParams.y;
const vec2 m = vec2(0.5, 0.5 / prop);
const vec2 d = (uv*_ScreenParams.xy) /_ScreenParams.x - m;
const float r = sqrt(dot(d, d));
float bind;
float power = ( 2.0 * 3.141592 / (2.0 * sqrt(dot(m, m))) ) *
(bend/50.0 - 0.5); //amount of effect
if (power > 0.0) bind = sqrt(dot(m, m));//stick to corners
else {if (prop < 1.0) bind = m.x; else bind = m.x;}//stick to borders
if (power > 0.0) //fisheye
uv = m + normalize(d) * tan(r * power) * bind / tan( bind * power);
else if (power < 0.0) //antifisheye
uv = m + normalize(d) * atan(r * -power * 10.0) * bind / atan(-power * bind * 10.0);
else uv = (uv*_ScreenParams.xy) /_ScreenParams.x;
uv.y *= prop;
}
//adjust size
// uv -= vec2(0.5,0.5);
// uv *= size;
// uv += vec2(0.5,0.5);
return uv;
}
//pulse vignette
float vignette(vec2 uv, float t)
{
const float vigAmt = 2.5+0.1*sin(t + 5.0*cos(t*5.0));
float c = (1.0-vigAmt*(uv.y-0.5)*(uv.y-0.5))*(1.0-vigAmt*(uv.x-0.5)*(uv.x-0.5));
c = pow(abs(c), vignetteAmount); //expensive!
return c;
}
vec3 t2d(vec2 p)
{
return rgb2yiq( texture (SamplerColorVHS, p ).rgb );
}
vec3 yiqDist(vec2 uv, float m, float t)
{
m *= 0.0001; // float m = 0.0009;
vec3 offsetX = vec3( uv.x, uv.x, uv.x );
offsetX.r += rnd_rd(vec2(t*0.03, uv.y*0.42)) * 0.001 + sin(rnd_rd(vec2(t*0.2, uv.y)))*m;
offsetX.g += rnd_rd(vec2(t*0.004,uv.y*0.002)) * 0.004 + sin(t*9.0)*m;
// offsetX.b = uv.y + rnd_rd(vec2(cos(t*0.01),sin(uv.y)))*m;
// offsetX.b = uv.y + rand_rd(vec2(cos(t*0.01),sin(uv.y)))*m;
vec3 signal = vec3(0.0, 0.0, 0.0);
//it cud be optimized / but hm
signal.x = rgb2yiq( texture( SamplerColorVHS, vec2(offsetX.r, uv.y) ).rgb ).x;
signal.y = rgb2yiq( texture( SamplerColorVHS, vec2(offsetX.g, uv.y) ).rgb ).y;
signal.z = rgb2yiq( texture( SamplerColorVHS, vec2(offsetX.b, uv.y) ).rgb ).z;
// signal = yiq2rgb(col);
return signal;
}
#define fixCoord (p - vec2( 0.5 * PixelSize.x, .0))
#define fetch_offset(offset, one_x) t2d(fixCoord + vec2( (offset) * (ONE_X), 0.0));
vec3 bm_screen(vec3 a, vec3 b){ return 1.0- (1.0-a)*(1.0-b); }