Home Reference Source

src/passes/FilmPass.js

import { Vector2 } from "three";
import { FilmMaterial } from "../materials";
import { Pass } from "./Pass.js";

/**
 * A film pass.
 *
 * Provides various cinematic effects.
 */

export class FilmPass extends Pass {

	/**
	 * Constructs a new film pass.
	 *
	 * @param {Object} [options] - The options. See {@link FilmMaterial} for more options.
	 * @param {Number} [options.scanlineDensity=1.25] - The scanline density, relative to the screen height.
	 * @param {Number} [options.gridScale=1.0] - The grid scale, relative to the screen height.
	 * @param {Number} [options.gridLineWidth=0.0] - The grid line width. This value will be added to the base line width.
	 */

	constructor(options = {}) {

		super("FilmPass");

		this.setFullscreenMaterial(new FilmMaterial(options));

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

		this.resolution = new Vector2();

		/**
		 * The amount of scanlines, relative to the screen height.
		 *
		 * @type {Number}
		 * @private
		 */

		this.scanlineDensity = (options.scanlineDensity === undefined) ? 1.25 : options.scanlineDensity;

		/**
		 * The grid scale, relative to the screen height.
		 *
		 * @type {Number}
		 * @private
		 */

		this.gridScale = (options.gridScale === undefined) ? 1.0 : Math.max(options.gridScale, 1e-6);

		/**
		 * The grid line width.
		 *
		 * @type {Number}
		 * @private
		 */

		this.gridLineWidth = (options.gridLineWidth === undefined) ? 0.0 : Math.max(options.gridLineWidth, 0.0);

	}

	/**
	 * Returns the current scanline density.
	 *
	 * @return {Number} The scanline density.
	 */

	getScanlineDensity() {

		return this.scanlineDensity;

	}

	/**
	 * Sets the scanline density.
	 *
	 * @param {Number} density - The new scanline density.
	 */

	setScanlineDensity(density) {

		this.scanlineDensity = density;
		this.setSize(this.resolution.x, this.resolution.y);

	}

	/**
	 * Returns the current grid scale.
	 *
	 * @return {Number} The grid scale.
	 */

	getGridScale() {

		return this.gridScale;

	}

	/**
	 * Sets the grid scale.
	 *
	 * @param {Number} scale - The new grid scale.
	 */

	setGridScale(scale) {

		this.gridScale = scale;
		this.setSize(this.resolution.x, this.resolution.y);

	}

	/**
	 * Returns the current grid line width.
	 *
	 * @return {Number} The grid line width.
	 */

	getGridLineWidth() {

		return this.gridLineWidth;

	}

	/**
	 * Sets the grid line width.
	 *
	 * @param {Number} lineWidth - The new grid line width.
	 */

	setGridLineWidth(lineWidth) {

		this.gridLineWidth = lineWidth;
		this.setSize(this.resolution.x, this.resolution.y);

	}

	/**
	 * Renders the effect.
	 *
	 * @param {WebGLRenderer} renderer - The renderer.
	 * @param {WebGLRenderTarget} inputBuffer - A frame buffer that contains the result of the previous pass.
	 * @param {WebGLRenderTarget} outputBuffer - A frame buffer that serves as the output render target unless this pass renders to screen.
	 * @param {Number} [delta] - The time between the last frame and the current one in seconds.
	 * @param {Boolean} [stencilTest] - Indicates whether a stencil mask is active.
	 */

	render(renderer, inputBuffer, outputBuffer, delta, stencilTest) {

		const uniforms = this.getFullscreenMaterial().uniforms;

		uniforms.tDiffuse.value = inputBuffer.texture;
		uniforms.time.value += delta;

		renderer.render(this.scene, this.camera, this.renderToScreen ? null : outputBuffer);

	}

	/**
	 * Updates the size of this pass.
	 *
	 * @param {Number} width - The width.
	 * @param {Number} height - The height.
	 */

	setSize(width, height) {

		// Remember the original resolution.
		this.resolution.set(width, height);

		const aspect = width / height;
		const gridScale = this.gridScale * (height * 0.125);

		const uniforms = this.getFullscreenMaterial().uniforms;
		uniforms.scanlineCount.value = Math.round(height * this.scanlineDensity);
		uniforms.gridScale.value.set(aspect * gridScale, gridScale);
		uniforms.gridLineWidth.value = (gridScale / height) + this.gridLineWidth;

	}

}