Home Reference Source

src/materials/LuminosityMaterial.js

import { ShaderMaterial, Uniform, Vector2 } from "three";

import fragment from "./glsl/luminosity/shader.frag";
import vertex from "./glsl/luminosity/shader.vert";

/**
 * A luminosity shader material.
 *
 * This shader produces a greyscale luminance map that describes the absolute
 * amount of light emitted by a scene. It can also be configured to output
 * colours that are scaled with their respective luminance value. Additionally,
 * a range may be provided to mask out undesired texels.
 *
 * The alpha channel will remain unaffected in all cases.
 *
 * On luminance coefficients:
 *  http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC9
 *
 * Coefficients for different colour spaces:
 *  https://hsto.org/getpro/habr/post_images/2ab/69d/084/2ab69d084f9a597e032624bcd74d57a7.png
 *
 * Luminance range reference:
 *  https://cycling74.com/2007/05/23/your-first-shader/#.Vty9FfkrL4Z
 */

export class LuminosityMaterial extends ShaderMaterial {

	/**
	 * Constructs a new luminosity material.
	 *
	 * @param {Boolean} [colorOutput=false] - Defines whether the shader should output colours scaled with their luminance value.
	 * @param {Vector2} [luminanceRange] - If provided, the shader will mask out texels that aren't in the specified luminance range.
	 */

	constructor(colorOutput = false, luminanceRange = null) {

		const maskLuminance = (luminanceRange !== null);

		super({

			type: "LuminosityMaterial",

			uniforms: {

				tDiffuse: new Uniform(null),
				distinction: new Uniform(1.0),
				range: new Uniform(maskLuminance ? luminanceRange : new Vector2())

			},

			fragmentShader: fragment,
			vertexShader: vertex

		});

		this.setColorOutputEnabled(colorOutput);
		this.setLuminanceRangeEnabled(maskLuminance);

	}

	/**
	 * Enables or disables color output.
	 *
	 * @param {Boolean} enabled - Whether color output should be enabled.
	 */

	setColorOutputEnabled(enabled) {

		if(enabled) {

			this.defines.COLOR = "1";

		} else {

			delete this.defines.COLOR;

		}

		this.needsUpdate = true;

	}

	/**
	 * Enables or disables the luminance mask.
	 *
	 * @param {Boolean} enabled - Whether the luminance mask should be enabled.
	 */

	setLuminanceRangeEnabled(enabled) {

		if(enabled) {

			this.defines.RANGE = "1";

		} else {

			delete this.defines.RANGE;

		}

		this.needsUpdate = true;

	}

}