Home Reference Source

src/effects/TextureEffect.js

import { LinearEncoding, Matrix3, sRGBEncoding, Uniform } from "three";
import { BlendFunction } from "./blending/BlendFunction.js";
import { Effect } from "./Effect.js";

import fragmentShader from "./glsl/texture/shader.frag";
import vertexShader from "./glsl/texture/shader.vert";

/**
 * A texture effect.
 */

export class TextureEffect extends Effect {

	/**
	 * Constructs a new texture effect.
	 *
	 * @param {Object} [options] - The options.
	 * @param {BlendFunction} [options.blendFunction=BlendFunction.NORMAL] - The blend function of this effect.
	 * @param {Texture} [options.texture] - A texture.
	 * @param {Boolean} [options.aspectCorrection=false] - Deprecated. Enable uvTransform instead and adjust the texture's offset, repeat and center.
	 */

	constructor({ blendFunction = BlendFunction.NORMAL, texture = null, aspectCorrection = false } = {}) {

		super("TextureEffect", fragmentShader, {

			blendFunction,

			uniforms: new Map([
				["texture", new Uniform(null)]
			])

		});

		this.texture = texture;
		this.aspectCorrection = aspectCorrection;

	}

	/**
	 * The texture.
	 *
	 * @type {Texture}
	 */

	get texture() {

		return this.uniforms.get("texture").value;

	}

	/**
	 * Sets the texture.
	 *
	 * You'll need to call {@link EffectPass#recompile} if you switch to a texture
	 * that uses a different encoding.
	 *
	 * @type {Texture}
	 */

	set texture(value) {

		this.uniforms.get("texture").value = value;

		if(value !== null) {

			if(value.encoding === sRGBEncoding) {

				this.defines.set("texelToLinear(texel)", "sRGBToLinear(texel)");

			} else if(value.encoding === LinearEncoding) {

				this.defines.set("texelToLinear(texel)", "texel");

			} else {

				console.log("unsupported encoding: " + value.encoding);

			}

		}

	}

	/**
	 * Indicates whether aspect correction is enabled.
	 *
	 * If enabled, the texture can be scaled using the `scale` uniform.
	 *
	 * @type {Number}
	 * @deprecated Use uvTransform instead for full control over the texture coordinates.
	 */

	get aspectCorrection() {

		return this.defines.has("ASPECT_CORRECTION");

	}

	/**
	 * Enables or disables aspect correction.
	 *
	 * You'll need to call {@link EffectPass#recompile} after changing this value.
	 *
	 * @type {Number}
	 * @deprecated Use uvTransform instead for full control over the texture coordinates.
	 */

	set aspectCorrection(value) {

		if(value) {

			if(this.uvTransform) {

				this.uvTransform = false;

			}

			this.defines.set("ASPECT_CORRECTION", "1");
			this.uniforms.set("scale", new Uniform(1.0));
			this.vertexShader = vertexShader;

		} else {

			this.defines.delete("ASPECT_CORRECTION");
			this.uniforms.delete("scale");
			this.vertexShader = null;

		}

	}

	/**
	 * Indicates whether the texture UV coordinates will be transformed using the
	 * transformation matrix of the texture.
	 *
	 * Cannot be used if aspect correction is enabled.
	 *
	 * @type {Number}
	 */

	get uvTransform() {

		return this.defines.has("UV_TRANSFORM");

	}

	/**
	 * Enables or disables texture UV transformation.
	 *
	 * You'll need to call {@link EffectPass#recompile} after changing this value.
	 *
	 * @type {Number}
	 */

	set uvTransform(value) {

		if(value) {

			if(this.aspectCorrection) {

				this.aspectCorrection = false;

			}

			this.defines.set("UV_TRANSFORM", "1");
			this.uniforms.set("uvTransform", new Uniform(new Matrix3()));
			this.vertexShader = vertexShader;

		} else {

			this.defines.delete("UV_TRANSFORM");
			this.uniforms.delete("uvTransform");
			this.vertexShader = null;

		}

	}

	/**
	 * Updates this effect.
	 *
	 * @param {WebGLRenderer} renderer - The renderer.
	 * @param {WebGLRenderTarget} inputBuffer - A frame buffer that contains the result of the previous pass.
	 * @param {Number} [deltaTime] - The time between the last frame and the current one in seconds.
	 */

	update(renderer, inputBuffer, deltaTime) {

		const texture = this.uniforms.get("texture").value;

		if(this.uvTransform && texture.matrixAutoUpdate) {

			texture.updateMatrix();
			this.uniforms.get("uvTransform").value.copy(texture.matrix);

		}

	}

}