FabricJS Filter Glitch

by codingdude

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.6/fabric.min.js"></script>
<script id="glitchShader" type="x-shader/x-vertex">
precision highp float;
uniform sampler2D uTexture;
uniform float uPhase;
uniform float uStepW,uStepH;
varying vec2 vTexCoord;
float sat( float t ) {
	return clamp( t, 0.0, 1.0 );
}

vec2 sat( vec2 t ) {
	return clamp( t, 0.0, 1.0 );
}
//remaps inteval [a;b] to [0;1]
float remap  ( float t, float a, float b ) {
	return sat( (t - a) / (b - a) );
}

//note: /\ t=[0;0.5;1], y=[0;1;0]
float linterp( float t ) {
	return sat( 1.0 - abs( 2.0*t - 1.0 ) );
}

vec3 spectrum_offset( float t ) {
    float t0 = 3.0 * t - 1.5;
	return clamp( vec3( -t0, 1.0-abs(t0), t0), 0.0, 1.0);
    /*
	vec3 ret;
	float lo = step(t,0.5);
	float hi = 1.0-lo;
	float w = linterp( remap( t, 1.0/6.0, 5.0/6.0 ) );
	float neg_w = 1.0-w;
	ret = vec3(lo,1.0,hi) * vec3(neg_w, w, neg_w);
	return pow( ret, vec3(1.0/2.2) );
*/
}

//note: [0;1]
float rand( vec2 n ) {
  return fract(sin(dot(n.xy, vec2(12.9898, 78.233)))* 43758.5453);
}

//note: [-1;1]
float srand( vec2 n ) {
	return rand(n) * 2.0 - 1.0;
}

float mytrunc( float x, float num_levels )
{
	return floor(x*num_levels) / num_levels;
}
vec2 mytrunc( vec2 x, float num_levels )
{
	return floor(x*num_levels) / num_levels;
}
void main() {
		float aspect = uStepW / uStepH;
		vec2 uv = vec2(vTexCoord.x,1.0 - vTexCoord.y); // vec2(uStepW,uStepH);
    uv.y = 1.0 - uv.y;
    float GLITCH = 0.4;
    float gnm = sat( GLITCH );
    float time = uPhase;
    float rnd0 = rand( mytrunc( vec2(time, time), 6.0 ) );
		float r0 = sat((1.0-gnm)*0.7 + rnd0);
		float rnd1 = rand( vec2(mytrunc( uv.x, 10.0*r0 ), time) ); //horz
		
		float r1 = 0.5 - 0.5 * gnm + rnd1;
		r1 = 1.0 - max( 0.0, ((r1<1.0) ? r1 : 0.9999999) ); //note: weird ass bug on old drivers
		float rnd2 = rand( vec2(mytrunc( uv.y, 40.0*r1 ), time) ); //vert
		float r2 = sat( rnd2 );

		float rnd3 = rand( vec2(mytrunc( uv.y, 10.0*r0 ), time) );
		float r3 =...

JavaScript

fabric.textureSize = 4096;//for filters on large images
var canvas = new fabric.Canvas('c');
var imgElement = document.getElementById('my-image');
var imgInstance = new fabric.Image(imgElement, {
  left: 100,
  top: 50,
  angle: 0,
  opacity: 1,
  scaleX:0.1,
  scaleY:0.1
});
canvas.add(imgInstance);



fabric.Image.filters.Glitch = fabric.util.createClass(fabric.Image.filters.BaseFilter, {

  type: 'Glitch',
	radius:0.1,
  smoothness:0.5,
  mainParameter:"phase",
  /**
   * Fragment source for the redify program
   */
  fragmentSource: window.document.getElementById("glitchShader").textContent,

  applyTo2d: function(options) {
    var imageData = options.imageData,
        data = imageData.data, i, len = data.length;

    for (i = 0; i < len; i += 4) {
      data[i + 1] = 0;
      data[i + 2] = 0;
    }

  },
  getUniformLocations: function(gl, program) {
      return {
        uPhase: gl.getUniformLocation(program, 'uPhase')
      };
    },
  sendUniformData: function(gl, uniformLocations) {
      gl.uniform1f(uniformLocations.uPhase, this.phase);
    }
});

fabric.Image.filters.Glitch.fromObject = fabric.Image.filters.BaseFilter.fromObject;

var glitch = new fabric.Image.filters.Glitch({phase:0.5});
imgInstance.filters.push(glitch);
imgInstance.applyFilters();

var slider = window.document.getElementById("phase");
slider.oninput = slider.onchange = function(){
	glitch.phase = this.value;
  console.log(this.value);
  imgInstance.applyFilters();
  canvas.requestRenderAll();
}