src/shaders/shaders.contour.fragment.js

Summary

Maintainability
D
2 days
Test Coverage
export default class ShadersFragment {
  // pass uniforms object
  constructor(uniforms) {
    this._uniforms = uniforms;
    this._functions = {};
    this._main = '';
  }

  functions() {
    if (this._main === '') {
      // if main is empty, functions can not have been computed
      this.main();
    }

    let content = '';
    for (let property in this._functions) {
      content += this._functions[property] + '\n';
    }

    return content;
  }

  uniforms() {
    let content = '';
    for (let property in this._uniforms) {
      let uniform = this._uniforms[property];
      content += `uniform ${uniform.typeGLSL} ${property}`;

      if (uniform && uniform.length) {
        content += `[${uniform.length}]`;
      }

      content += ';\n';
    }

    return content;
  }

  main() {
    // need to pre-call main to fill up the functions list
    this._main = `

float luma (vec3 rgb) {
  return (rgb.r + rgb.g + rgb.b)/3.0;
}

const float T = 0.04;
const float M = 1.0;
const float L = 0.002;

void main(void) {

  vec2 texCoord = vec2(((vProjectedCoords.x / vProjectedCoords.w) + 1.0 ) / 2.0,
                ((vProjectedCoords.y / vProjectedCoords.w) + 1.0 ) / 2.0 );

  float borderWidth = uWidth; // in px
  float step_u = borderWidth * 1.0 / uCanvasWidth;
  float step_v = borderWidth * 1.0 / uCanvasHeight;
  vec4 centerPixel = texture2D(uTextureFilled, texCoord);

  vec4 rightPixel  = texture2D(uTextureFilled, texCoord + vec2(step_u, 0.0));
  vec4 bottomPixel = texture2D(uTextureFilled, texCoord + vec2(0.0, step_v));

  // now manually compute the derivatives
  float _dFdX = length(rightPixel - centerPixel) / step_u;
  float _dFdY = length(bottomPixel - centerPixel) / step_v;

  // gl_FragColor.r = _dFdX;
  // gl_FragColor.g = _dFdY;
  gl_FragColor.r = max(max(centerPixel.r, rightPixel.r), bottomPixel.r);
  gl_FragColor.g = max(max(centerPixel.g, rightPixel.g), bottomPixel.g);
  gl_FragColor.b = max(max(centerPixel.b, rightPixel.b), bottomPixel.b);
  float maxDerivative = max(_dFdX, _dFdY);
  float clampedDerivative = clamp(maxDerivative, 0., 1.);
  gl_FragColor.a = uOpacity * clampedDerivative;

  return;
  // float h = 1./uCanvasHeight;
  // float w = 1./uCanvasWidth;
  // vec4 n[9];
  // n[0] = texture2D(uTextureFilled, vProjectedTextCoords + vec2( -w, -h));
  // n[1] = texture2D(uTextureFilled, vProjectedTextCoords + vec2(0.0, -h));
  // n[2] = texture2D(uTextureFilled, vProjectedTextCoords + vec2(  w, -h));
  // n[3] = texture2D(uTextureFilled, vProjectedTextCoords + vec2( -w, 0.0));
  // n[4] = texture2D(uTextureFilled, vProjectedTextCoords);
  // n[5] = texture2D(uTextureFilled, texCoord + vec2(  w, 0.0));
  // n[6] = texture2D(uTextureFilled, texCoord + vec2( -w, h));
  // n[7] = texture2D(uTextureFilled, texCoord + vec2(0.0, h));
  // n[8] = texture2D(uTextureFilled, texCoord + vec2(  w, h));
  // vec4 sobel_horizEdge = n[2] + (2.0*n[5]) + n[8] - (n[0] + (2.0*n[3]) + n[6]);
  // vec4 sobel_vertEdge  = n[0] + (2.0*n[1]) + n[2] - (n[6] + (2.0*n[7]) + n[8]);
  // vec3 sobel = sqrt((sobel_horizEdge.rgb * sobel_horizEdge.rgb) + (sobel_vertEdge.rgb * sobel_vertEdge.rgb));
  // gl_FragColor = vec4( sobel, max(max(sobel.r, sobel.g), sobel.b) );

  // return;
}
   `;
  }

  compute() {
    let shaderInterpolation = '';
    // shaderInterpolation.inline(args) //true/false
    // shaderInterpolation.functions(args)

    return `
// uniforms
${this.uniforms()}

// varying (should fetch it from vertex directly)
varying vec4      vProjectedCoords;

// tailored functions
${this.functions()}

// main loop
${this._main}
      `;
  }
}