Home Reference Source

src/effects/PixelationEffect.js

import { Uniform, Vector2, Vector4 } from "three";
import { Effect } from "./Effect.js";

import fragmentShader from "./glsl/pixelation.frag";

/**
 * A pixelation effect.
 *
 * Warning: This effect cannot be merged with convolution effects.
 */

export class PixelationEffect extends Effect {

	/**
	 * Constructs a new pixelation effect.
	 *
	 * @param {Object} [granularity=30.0] - The pixel granularity.
	 */

	constructor(granularity = 30.0) {

		super("PixelationEffect", fragmentShader, {
			uniforms: new Map([
				["active", new Uniform(false)],
				["d", new Uniform(new Vector4())]
			])
		});

		/**
		 * The original resolution.
		 *
		 * @type {Vector2}
		 * @private
		 */

		this.resolution = new Vector2();

		/**
		 * Backing data for {@link granularity}.
		 *
		 * @type {Number}
		 * @private
		 */

		this._granularity = 0;
		this.granularity = granularity;

	}

	/**
	 * The pixel granularity.
	 *
	 * A higher value yields coarser visuals.
	 *
	 * @type {Number}
	 */

	get granularity() {

		return this._granularity;

	}

	set granularity(value) {

		let d = Math.floor(value);

		if(d % 2 > 0) {

			d += 1;

		}

		this._granularity = d;
		this.uniforms.get("active").value = (d > 0);
		this.setSize(this.resolution.width, this.resolution.height);

	}

	/**
	 * Returns the pixel granularity.
	 *
	 * @deprecated Use granularity instead.
	 * @return {Number} The granularity.
	 */

	getGranularity() {

		return this.granularity;

	}

	/**
	 * Sets the pixel granularity.
	 *
	 * @deprecated Use granularity instead.
	 * @param {Number} value - The new granularity.
	 */

	setGranularity(value) {

		this.granularity = value;

	}

	/**
	 * Updates the granularity.
	 *
	 * @param {Number} width - The width.
	 * @param {Number} height - The height.
	 */

	setSize(width, height) {

		const resolution = this.resolution;
		resolution.set(width, height);

		const d = this.granularity;
		const x = d / resolution.x;
		const y = d / resolution.y;
		this.uniforms.get("d").value.set(x, y, 1.0 / x, 1.0 / y);

	}

}