Extensions

Source: filters/FXAAFilter.js

import { BaseFilter } from "./BaseFilter";

// prettier-ignore
const _GLSL = "ivec2 " +
    "faM=ivec2(ts)-1;" +
  "vec3 " +
    "faL=vec3(.299,.587,.114);" +
  "vec4 " +
    "faNW=texelFetch(uB,clamp(f-1,ivec2(0),faM),0)," +
    "faNE=texelFetch(uB,clamp(f+ivec2(1,-1),ivec2(0),faM),0)," +
    "faSW=texelFetch(uB,clamp(f+ivec2(-1,1),ivec2(0),faM),0)," +
    "faSE=texelFetch(uB,clamp(f+1,ivec2(0),faM),0);" +
  "float " +
    "lNW=dot(faNW.rgb/max(faNW.a,1e-4),faL)," +
    "lNE=dot(faNE.rgb/max(faNE.a,1e-4),faL)," +
    "lSW=dot(faSW.rgb/max(faSW.a,1e-4),faL)," +
    "lSE=dot(faSE.rgb/max(faSE.a,1e-4),faL)," +
    "lM=dot(oCl.rgb/max(oCl.a,1e-4),faL)," +
    "lMin=min(lM,min(min(lNW,lNE),min(lSW,lSE)))," +
    "lMax=max(lM,max(max(lNW,lNE),max(lSW,lSE)));" +
  "vec2 " +
    "faD=vec2(lSW+lSE-lNW-lNE,lNW+lSW-lNE-lSE);" +
  "float " +
    "faR=max((lNW+lNE+lSW+lSE)*.25*uL[0].y,uL[0].z);" +
  "faD=clamp(faD/(min(abs(faD.x),abs(faD.y))+faR),-uL[0].x,uL[0].x)/ts;" +
  "vec4 " +
    "faA=.5*(texture(uB,v0.zw-faD/6.)+texture(uB,v0.zw+faD/6.))," +
    "faB=faA*.5+.25*(texture(uB,v0.zw-faD*.5)+texture(uB,v0.zw+faD*.5));" +
  "float " +
    "lB=dot(faB.rgb/max(faB.a,1e-4),faL);" +
  "oCl=lB<lMin||lB>lMax?faA:faB;";

/**
 * <pre>
 *  FXAA filter
 *    - Lightweight fast approximate anti-aliasing (5 luma taps and one directional span)
 *    - The intensity is unused, use mix to control the strength
 * </pre>
 * @extends {BaseFilter}
 */
export class FXAAFilter extends BaseFilter {
  /**
   * Creates an instance of FXAAFilter.
   * @constructor
   * @param {object} options
   * @param {number} options.spanMax - Default value 8 <br>
   *                                 - Maximum blur span in pixels
   * @param {number} options.reduceMul - Default value 1/8 <br>
   *                                   - Direction reduce multiplier
   * @param {number} options.reduceMin - Default value 1/128 <br>
   *                                   - Minimum direction reduce
   */
  constructor(options = {}) {
    super(options);

    this.spanMax = options.spanMax ?? 8;
    this.reduceMul = options.reduceMul ?? 1 / 8;
    this.reduceMin = options.reduceMin ?? 1 / 128;
  }

  get GLSL() {
    return _GLSL;
  }

  /**
   * Set/Get maximum span in pixels
   * @type {number}
   */
  get spanMax() {
    return this.customData[0];
  }
  set spanMax(v) {
    this.customData[0] = v;
  }

  /**
   * Set/Get reduce multiplier
   * @type {number}
   */
  get reduceMul() {
    return this.customData[1];
  }
  set reduceMul(v) {
    this.customData[1] = v;
  }

  /**
   * Set/Get minimum reduce
   * @type {number}
   */
  get reduceMin() {
    return this.customData[2];
  }
  set reduceMin(v) {
    this.customData[2] = v;
  }
}