UNPKG

solution

Version:

An animation library for different types of liquids.

232 lines (169 loc) 5.3 kB
import { DistortionMaterial, DropletNoiseMaterial } from "../materials"; import { Pass } from "postprocessing"; import THREE from "three"; /** * A distortion and droplet pass for underwater and wet lens effects. * * @class DistortionPass * @constructor * @param {Object} [options] - The options. * @param {Number} [options.resolution=512] - The size of the generated perturbation map, power of two. * @param {Vector2} [options.rollOffSpeed] - The droplet roll off speed. * @param {Vector2} [options.waveStrength] - The sine and cosine wave distortion strength. * @param {Boolean} [options.highQuality] - The effect quality. If set to true, double the amount of noise values will be computed. * @param {Number} [options.speed] - The effect's animation speed. */ export class DistortionPass extends Pass { constructor(options) { super(); this.needsSwap = true; if(options === undefined) { options = {}; } /** * Noise render texture. * * @property renderTargetPerturb * @type WebGLRenderTarget * @private */ this.renderTargetPerturb = new THREE.WebGLRenderTarget(1, 1, { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, // want RG16F or RG32F. type: THREE.FloatType, generateMipmaps: false, stencilBuffer: false, depthBuffer: false }); /** * Droplet noise shader material. * * @property noiseMaterial * @type DropletNoiseMaterial * @private */ this.noiseMaterial = new DropletNoiseMaterial(options.highQuality); this.resolution = (options.resolution === undefined) ? 512 : options.resolution; /** * Distortion shader material. * * @property distortionMaterial * @type DistortionMaterial * @private */ this.distortionMaterial = new DistortionMaterial({ perturbMap: this.renderTargetPerturb.texture, rollOffSpeed: options.rollOffSpeed, waveStrength: options.waveStrength, tint: options.color }); this.quad.material = this.distortionMaterial; /** * The effect speed. * * @property speed * @type Number */ this.speed = (options.speed === undefined) ? 1.0 : options.speed; /** * Maximum duration of the dissolution effect in seconds. * * @property dissolutionEnd * @type Number * @private */ this.dissolutionEnd = Number.parseFloat(this.distortionMaterial.defines.T_DROPLETS); /** * Dissolution flag. * * @property _dissolve * @type Boolean * @default false * @private */ this._dissolve = false; } /** * The resolution of the noise texture. * The value should be a power of two. * * @property resolution * @type Number * @default 512 */ get resolution() { return this.renderTargetPerturb.width; } set resolution(x) { if(typeof x === "number" && x > 0) { this.noiseMaterial.uniforms.tWidth.value = x; this.noiseMaterial.uniforms.tHeight.value = x; this.noiseMaterial.uniforms.texelSize.value = 1.0 / x; this.noiseMaterial.uniforms.halfTexelSize.value = 0.5 / x; this.renderTargetPerturb.setSize(x, x); } } /** * Dissolution flag. * * Set to false for wavy distortion, * set to true for dissolution into droplets. * * @property dissolve * @type Boolean * @default false */ get dissolve() { return this._dissolve; } set dissolve(x) { this._dissolve = x; if(!this._dissolve) { this.distortionMaterial.uniforms.resetTimer.value = 0.0; this.distortionMaterial.uniforms.time.value = Math.random() * 1000.0; this.noiseMaterial.uniforms.randomTime.value = Math.random() * 10.0 - 1.0; } } /** * Renders the effect. * * @method render * @param {WebGLRenderer} renderer - The renderer to use. * @param {WebGLRenderTarget} readBuffer - The read buffer. * @param {WebGLRenderTarget} writeBuffer - The write buffer. * @param {Number} delta - The render delta time. */ render(renderer, readBuffer, writeBuffer, delta) { let t = delta * this.speed; this.distortionMaterial.uniforms.tDiffuse.value = readBuffer; this.distortionMaterial.uniforms.time.value += t; //this.renderPerturbationMap(renderer); // Debug. if(this.dissolve && this.distortionMaterial.uniforms.resetTimer.value <= this.dissolutionEnd) { this.distortionMaterial.uniforms.resetTimer.value += t; this.renderPerturbationMap(renderer); } if(this.renderToScreen) { renderer.render(this.scene, this.camera); } else { renderer.render(this.scene, this.camera, writeBuffer, false); } } /** * Renders a perturbation noise map. * * @method renderPerturbationMap * @param {WebGLRenderer} renderer - The renderer to use. * @private */ renderPerturbationMap(renderer) { this.quad.material = this.noiseMaterial; this.noiseMaterial.uniforms.time.value = this.distortionMaterial.uniforms.time.value; //renderer.render(this.scene, this.camera); // Renders the perturb map to screen. renderer.render(this.scene, this.camera, this.renderTargetPerturb, false); this.quad.material = this.distortionMaterial; } /** * Warms up the perturbation render target to avoid start-up hiccups. * * @method initialise * @param {WebGLRenderer} renderer - The renderer. */ initialise(renderer) { this.renderPerturbationMap(renderer); } }