UNPKG

three

Version:

JavaScript 3D library

267 lines (203 loc) 5.74 kB
import { HalfFloatType, ShaderMaterial, WebGLRenderTarget } from 'three'; import { FullScreenQuad, Pass } from './Pass.js'; /** * A special type of render pass for implementing transition effects. * When active, the pass will transition from scene A to scene B. * * ```js * const renderTransitionPass = new RenderTransitionPass( fxSceneA.scene, fxSceneA.camera, fxSceneB.scene, fxSceneB.camera ); * renderTransitionPass.setTexture( textures[ 0 ] ); * composer.addPass( renderTransitionPass ); * ``` * * @augments Pass */ class RenderTransitionPass extends Pass { /** * Constructs a render transition pass. * * @param {Scene} sceneA - The first scene. * @param {Camera} cameraA - The camera of the first scene. * @param {Scene} sceneB - The second scene. * @param {Camera} cameraB - The camera of the second scene. */ constructor( sceneA, cameraA, sceneB, cameraB ) { super(); /** * The first scene. * * @type {Scene} */ this.sceneA = sceneA; /** * The camera of the first scene. * * @type {Camera} */ this.cameraA = cameraA; /** * The second scene. * * @type {Scene} */ this.sceneB = sceneB; /** * The camera of the second scene. * * @type {Camera} */ this.cameraB = cameraB; /** * The pass material. * * @type {ShaderMaterial} */ this.material = this._createMaterial(); // internals this._renderTargetA = new WebGLRenderTarget(); this._renderTargetA.texture.type = HalfFloatType; this._renderTargetB = new WebGLRenderTarget(); this._renderTargetB.texture.type = HalfFloatType; this._fsQuad = new FullScreenQuad( this.material ); } /** * Sets the transition factor. Must be in the range `[0,1]`. * This value determines to what degree both scenes are mixed. * * @param {boolenumberan} value - The transition factor. */ setTransition( value ) { this.material.uniforms.mixRatio.value = value; } /** * Toggles the usage of a texture for the effect. * * @param {boolean} value - Whether to use a texture for the transition effect or not. */ useTexture( value ) { this.material.uniforms.useTexture.value = value ? 1 : 0; } /** * Sets the effect texture. * * @param {Texture} value - The effect texture. */ setTexture( value ) { this.material.uniforms.tMixTexture.value = value; } /** * Sets the texture threshold. This value defined how strong the texture effects * the transition. Must be in the range `[0,1]` (0 means full effect, 1 means no effect). * * @param {boolenumberan} value - The threshold value. */ setTextureThreshold( value ) { this.material.uniforms.threshold.value = value; } /** * Sets the size of the pass. * * @param {number} width - The width to set. * @param {number} height - The width to set. */ setSize( width, height ) { this._renderTargetA.setSize( width, height ); this._renderTargetB.setSize( width, height ); } /** * Performs the transition pass. * * @param {WebGLRenderer} renderer - The renderer. * @param {WebGLRenderTarget} writeBuffer - The write buffer. This buffer is intended as the rendering * destination for the pass. * @param {WebGLRenderTarget} readBuffer - The read buffer. The pass can access the result from the * previous pass from this buffer. * @param {number} deltaTime - The delta time in seconds. * @param {boolean} maskActive - Whether masking is active or not. */ render( renderer, writeBuffer/*, readBuffer , deltaTime, maskActive */ ) { renderer.setRenderTarget( this._renderTargetA ); renderer.render( this.sceneA, this.cameraA ); renderer.setRenderTarget( this._renderTargetB ); renderer.render( this.sceneB, this.cameraB ); const uniforms = this._fsQuad.material.uniforms; uniforms.tDiffuse1.value = this._renderTargetA.texture; uniforms.tDiffuse2.value = this._renderTargetB.texture; if ( this.renderToScreen ) { renderer.setRenderTarget( null ); renderer.clear(); } else { renderer.setRenderTarget( writeBuffer ); if ( this.clear ) renderer.clear(); } this._fsQuad.render( renderer ); } /** * Frees the GPU-related resources allocated by this instance. Call this * method whenever the pass is no longer used in your app. */ dispose() { this.material.dispose(); this._renderTargetA.dispose(); this._renderTargetB.dispose(); this._fsQuad.dispose(); } // internals _createMaterial() { return new ShaderMaterial( { uniforms: { tDiffuse1: { value: null }, tDiffuse2: { value: null }, mixRatio: { value: 0.0 }, threshold: { value: 0.1 }, useTexture: { value: 1 }, tMixTexture: { value: null } }, vertexShader: /* glsl */` varying vec2 vUv; void main() { vUv = vec2( uv.x, uv.y ); gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); } `, fragmentShader: /* glsl */` uniform float mixRatio; uniform sampler2D tDiffuse1; uniform sampler2D tDiffuse2; uniform sampler2D tMixTexture; uniform int useTexture; uniform float threshold; varying vec2 vUv; void main() { vec4 texel1 = texture2D( tDiffuse1, vUv ); vec4 texel2 = texture2D( tDiffuse2, vUv ); if (useTexture == 1) { vec4 transitionTexel = texture2D( tMixTexture, vUv ); float r = mixRatio * ( 1.0 + threshold * 2.0 ) - threshold; float mixf = clamp( ( transitionTexel.r - r ) * ( 1.0 / threshold ), 0.0, 1.0 ); gl_FragColor = mix( texel1, texel2, mixf ); } else { gl_FragColor = mix( texel2, texel1, mixRatio ); } } ` } ); } } export { RenderTransitionPass };