Home Reference Source

src/materials/GodRaysMaterial.js

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

import fragmentShader from "./glsl/convolution.god-rays.frag";
import vertexShader from "./glsl/common.vert";

/**
 * A crepuscular rays shader material.
 *
 * References:
 *
 * Thibaut Despoulain, 2012: [(WebGL) Volumetric Light Approximation in Three.js](
 * http://bkcore.com/blog/3d/webgl-three-js-volumetric-light-godrays.html)
 * Nvidia, GPU Gems 3, 2008: [Chapter 13. Volumetric Light Scattering as a Post-Process](
 * https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch13.html)
 *
 * @todo Remove dithering code from fragment shader.
 */

export class GodRaysMaterial extends ShaderMaterial {

	/**
	 * Constructs a new god rays material.
	 *
	 * TODO Remove lightPosition param.
	 * @param {Vector2} lightPosition - Deprecated.
	 */

	constructor(lightPosition) {

		super({
			name: "GodRaysMaterial",
			defines: {
				SAMPLES_INT: "60",
				SAMPLES_FLOAT: "60.0"
			},
			uniforms: {
				inputBuffer: new Uniform(null),
				lightPosition: new Uniform(lightPosition),
				density: new Uniform(1.0),
				decay: new Uniform(1.0),
				weight: new Uniform(1.0),
				exposure: new Uniform(1.0),
				clampMax: new Uniform(1.0)
			},
			blending: NoBlending,
			toneMapped: false,
			depthWrite: false,
			depthTest: false,
			fragmentShader,
			vertexShader
		});

	}

	/**
	 * The input buffer.
	 *
	 * @type {Texture}
	 */

	set inputBuffer(value) {

		this.uniforms.inputBuffer.value = value;

	}

	/**
	 * Sets the input buffer.
	 *
	 * @deprecated Use inputBuffer instead.
	 * @param {Texture} value - The input buffer.
	 */

	setInputBuffer(value) {

		this.uniforms.inputBuffer.value = value;

	}

	/**
	 * The screen space position of the light source.
	 *
	 * @type {Vector2}
	 */

	get lightPosition() {

		return this.uniforms.lightPosition.value;

	}

	/**
	 * Returns the screen space position of the light source.
	 *
	 * @deprecated Use lightPosition instead.
	 * @return {Vector2} The position.
	 */

	getLightPosition() {

		return this.uniforms.lightPosition.value;

	}

	/**
	 * Sets the screen space position of the light source.
	 *
	 * @deprecated Use lightPosition instead.
	 * @param {Vector2} value - The position.
	 */

	setLightPosition(value) {

		this.uniforms.lightPosition.value = value;

	}

	/**
	 * The density.
	 *
	 * @type {Number}
	 */

	get density() {

		return this.uniforms.density.value;

	}

	set density(value) {

		this.uniforms.density.value = value;

	}

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

	getDensity() {

		return this.uniforms.density.value;

	}

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

	setDensity(value) {

		this.uniforms.density.value = value;

	}

	/**
	 * The decay.
	 *
	 * @type {Number}
	 */

	get decay() {

		return this.uniforms.decay.value;

	}

	set decay(value) {

		this.uniforms.decay.value = value;

	}

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

	getDecay() {

		return this.uniforms.decay.value;

	}

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

	setDecay(value) {

		this.uniforms.decay.value = value;

	}

	/**
	 * The weight.
	 *
	 * @type {Number}
	 */

	get weight() {

		return this.uniforms.weight.value;

	}

	set weight(value) {

		this.uniforms.weight.value = value;

	}

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

	getWeight() {

		return this.uniforms.weight.value;

	}

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

	setWeight(value) {

		this.uniforms.weight.value = value;

	}

	/**
	 * The exposure.
	 *
	 * @type {Number}
	 */

	get exposure() {

		return this.uniforms.exposure.value;

	}

	set exposure(value) {

		this.uniforms.exposure.value = value;

	}

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

	getExposure() {

		return this.uniforms.exposure.value;

	}

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

	setExposure(value) {

		this.uniforms.exposure.value = value;

	}

	/**
	 * The maximum light intensity.
	 *
	 * @type {Number}
	 */

	get maxIntensity() {

		return this.uniforms.clampMax.value;

	}

	set maxIntensity(value) {

		this.uniforms.clampMax.value = value;

	}

	/**
	 * Returns the maximum light intensity.
	 *
	 * @deprecated Use maxIntensity instead.
	 * @return {Number} The maximum light intensity.
	 */

	getMaxIntensity() {

		return this.uniforms.clampMax.value;

	}

	/**
	 * Sets the maximum light intensity.
	 *
	 * @deprecated Use maxIntensity instead.
	 * @param {Number} value - The maximum light intensity.
	 */

	setMaxIntensity(value) {

		this.uniforms.clampMax.value = value;

	}

	/**
	 * The amount of samples per pixel.
	 *
	 * @type {Number}
	 */

	get samples() {

		return Number(this.defines.SAMPLES_INT);

	}

	set samples(value) {

		const s = Math.floor(value);
		this.defines.SAMPLES_INT = s.toFixed(0);
		this.defines.SAMPLES_FLOAT = s.toFixed(1);
		this.needsUpdate = true;

	}

	/**
	 * Returns the amount of samples per pixel.
	 *
	 * @deprecated Use samples instead.
	 * @return {Number} The sample count.
	 */

	getSamples() {

		return this.samples;

	}

	/**
	 * Sets the amount of samples per pixel.
	 *
	 * @deprecated Use samples instead.
	 * @param {Number} value - The sample count.
	 */

	setSamples(value) {

		this.samples = value;

	}

}