import { WebGLRenderTarget , WebGLRenderer , MathUtils } from 'three' ; import { Pass } from 'three/examples/jsm/postprocessing/Pass' ; import { CopyShader } from 'three/examples/jsm/shaders/CopyShader' ; import { EffectType , Effect , GaussianBlurEffect , BloomEffect , VignetteBlurEffect , GlitchEffect , IEffect , RGBShiftEffect , VignetteEffect } from '../effects/effect' ; type EffectTypeConfig < T extends Exclude < EffectType , EffectType . MotionBlur > > = { [ EffectType . Blur ] : BlurEffectConfig ; [ EffectType . Bloom ] : BloomEffectConfig ; [ EffectType . RgbShift ] : RgbShiftEffectConfig ; [ EffectType . Vignette ] : VignetteEffectConfig ; [ EffectType . VignetteBlur ] : VignetteBlurEffectConfig ; [ EffectType . Glitch ] : GlitchEffectConfig ; } [ T ] ; type EffectConfigs = { [ T in Exclude < EffectType , EffectType . MotionBlur > ] ? : EffectTypeConfig < T > ; } ; type EffectMap = Partial < Record < EffectType , IEffect > > ; type EffectConfig = BlurEffectConfig | BloomEffectConfig | RgbShiftEffectConfig | VignetteEffectConfig | VignetteBlurEffectConfig | GlitchEffectConfig ; interface BlurEffectConfig { radius ? : number ; passes ? : number ; } interface BloomEffectConfig { opacity ? : number ; radius ? : number ; passes ? : number ; } interface RgbShiftEffectConfig { amount ? : number ; angle ? : number ; } interface VignetteEffectConfig { offset ? : number ; darkness ? : number ; } interface VignetteBlurEffectConfig { size ? : number ; radius ? : number ; passes ? : number ; } interface GlitchEffectConfig { amount ? : number ; seed ? : number ; } class EffectPass extends Pass { private _width : number ; private _height : number ; private _readBuffer : WebGLRenderTarget ; private _writeBuffer : WebGLRenderTarget ; private _copyShader : Effect = new Effect ( CopyShader ) ; protected _effects : EffectMap = { } ; param { number } width param { number } height constructor ( width , height ) { super ( ) ; this . _width = width ; this . _height = height ; this . _readBuffer = new WebGLRenderTarget ( width , height ) ; this . _writeBuffer = new WebGLRenderTarget ( width , height ) ; this . enabled = false ; } param { number } width param { number } height setSize ( width , height ) { this . _width = width ; this . _height = height ; this . _readBuffer . setSize ( width , height ) ; this . _writeBuffer . setSize ( width , height ) ; for ( const effect of Object . values ( this . _effects ) ) { if ( effect . setSize ) { effect . setSize ( width , height ) ; } } } returns getConfigs ( ) { const configs = { } ; for ( const [ type , effect ] of Object . entries ( this . _effects ) ) { switch ( type ) { case EffectType . Blur : { const { radius } = effect . getUniforms ( ) ; configs [ type ] = { radius , passes : ( effect as GaussianBlurEffect ) . passes } ; break ; } case EffectType . Bloom : { const { opacity , radius } = effect . getUniforms ( ) ; configs [ type ] = { opacity , radius , passes : ( effect as BloomEffect ) . passes } ; break ; } case EffectType . RgbShift : { const { amount , angle } = effect . getUniforms ( ) ; configs [ type ] = { amount , angle : MathUtils . radToDeg ( angle as number ) } ; break ; } case EffectType . Vignette : { const { offset , darkness } = effect . getUniforms ( ) ; configs [ type ] = { offset , darkness } ; break ; } case EffectType . VignetteBlur : { const { size , radius } = effect . getUniforms ( ) ; configs [ type ] = { size , radius , passes : ( effect as VignetteBlurEffect ) . passes } ; break ; } case EffectType . Glitch : { const { amount , seed } = effect . getUniforms ( ) ; configs [ type ] = { amount , seed } ; break ; } } } return configs ; } param { EffectType } type returns hasEffect ( type ) { return this . _effects . hasOwnProperty ( type ) ; } returns hasEffects ( ) { return Object . getOwnPropertyNames ( this . _effects ) . length !== 0 ; } param { EffectType } type param { EffectConfig } config returns protected _getEffect ( type ) { if ( ! ( type in this . _effects ) ) { switch ( type ) { case EffectType . Blur : this . _effects [ type ] = new GaussianBlurEffect ( this . _width , this . _height ) ; break ; case EffectType . Bloom : this . _effects [ type ] = new BloomEffect ( this . _width , this . _height ) ; break ; case EffectType . RgbShift : this . _effects [ type ] = new RGBShiftEffect ( ) ; break ; case EffectType . Vignette : this . _effects [ type ] = new VignetteEffect ( ) ; break ; case EffectType . VignetteBlur : this . _effects [ type ] = new VignetteBlurEffect ( this . _width , this . _height ) ; break ; case EffectType . Glitch : this . _effects [ type ] = new GlitchEffect ( this . _width , this . _height ) ; break ; } } return this . _effects [ type ] ! ; } param { EffectType } type param { Object } config set < T extends Exclude < EffectType , EffectType . MotionBlur > > ( type , config = { } ) { const effect = this . _getEffect ( type ) ; this . enabled = true ; switch ( type ) { case EffectType . Blur : { const { radius = 1 , passes = ( effect as GaussianBlurEffect ) . passes } = config as BlurEffectConfig ; ( effect as GaussianBlurEffect ) . passes = passes ; effect . updateUniforms ( { radius } ) ; break ; } case EffectType . Bloom : { const { opacity = 1 , radius = 1 , passes = ( effect as BloomEffect ) . passes } = config as BloomEffectConfig ; ( effect as BloomEffect ) . passes = passes ; effect . updateUniforms ( { opacity , radius } ) ; break ; } case EffectType . RgbShift : { const { amount = 0.005 , angle = 0 } = config as RgbShiftEffectConfig ; effect . updateUniforms ( { amount , angle : MathUtils . degToRad ( angle ) } ) ; break ; } case EffectType . Vignette : { const { offset = 1 , darkness = 1 } = config as VignetteEffectConfig ; effect . updateUniforms ( { offset , darkness } ) ; break ; } case EffectType . VignetteBlur : { const { size = 1 , radius = 1 , passes = ( effect as VignetteBlurEffect ) . passes } = config as VignetteBlurEffectConfig ; ( effect as VignetteBlurEffect ) . passes = passes ; effect . updateUniforms ( { radius , size } ) ; break ; } case EffectType . Glitch : { const { amount = 1 , seed = Math . random ( ) } = config as GlitchEffectConfig ; effect . updateUniforms ( { amount , seed } ) ; break ; } } } param { EffectType } type returns remove ( type ) { if ( type in this . _effects ) { this . _effects [ type ] ! . dispose ( ) ; delete this . _effects [ type ] ; this . enabled = this . hasEffects ( ) ; return true ; } return false ; } /**
     * Removes all set effects.
     */ removeAll ( ) { for ( const type in this . _effects ) { this . _effects [ type ] . dispose ( ) ; delete this . _effects [ type ] ; } this . enabled = false ; } /**
     * Swaps the internal read and write buffers. Should be called each time after rendering an effect.
     */ private _swapBuffers ( ) { const tmp = this . _readBuffer ; this . _readBuffer = this . _writeBuffer ; this . _writeBuffer = tmp ; } param { WebGLRenderer } renderer param { WebGLRenderTarget | null } writeBuffer param { WebGLRenderTarget } readBuffer render ( renderer , writeBuffer , readBuffer ) { this . _copyShader . render ( renderer , this . _readBuffer , readBuffer ) ; for ( const effect of Object . values ( this . _effects ) ) { effect . render ( renderer , this . _writeBuffer , this . _readBuffer ) ; this . _swapBuffers ( ) ; } this . _copyShader . render ( renderer , this . renderToScreen ? null : writeBuffer , this . _readBuffer ) ; } /**
     * Disposes this object. Call when this object is no longer needed, otherwise leaks may occur.
     */ dispose ( ) { this . _copyShader . dispose ( ) ; this . _readBuffer . dispose ( ) ; this . _readBuffer . texture . dispose ( ) ; this . _writeBuffer . dispose ( ) ; this . _writeBuffer . texture . dispose ( ) ; Object . values ( this . _effects ) . forEach ( effect => effect . dispose ( ) ) ; } } export { EffectConfig , BlurEffectConfig , BloomEffectConfig , RgbShiftEffectConfig , VignetteEffectConfig , VignetteBlurEffectConfig , GlitchEffectConfig , EffectConfigs , EffectPass , } ; export default EffectPass ;