From de4834da549f669a82f25eb0f8272e45925147c0 Mon Sep 17 00:00:00 2001 From: Cody Bennett <23324155+CodyJasonBennett@users.noreply.github.com> Date: Fri, 26 May 2023 10:46:05 -0500 Subject: [PATCH] fix: tree-shake postprocessing --- src/index.ts | 56 +- .../AdaptiveToneMappingPass.d.ts | 4 +- src/postprocessing/AdaptiveToneMappingPass.js | 254 ++++--- src/postprocessing/CubeTexturePass.js | 89 +-- src/postprocessing/RenderPixelatedPass.d.ts | 28 + src/postprocessing/SAOPass.d.ts | 6 +- src/postprocessing/SAOPass.js | 345 +++++----- src/postprocessing/SSAARenderPass.d.ts | 4 +- src/postprocessing/SSAARenderPass.js | 272 ++++---- src/postprocessing/SSAOPass.d.ts | 4 +- src/postprocessing/SSAOPass.js | 18 +- src/postprocessing/SSRPass.js | 634 ++++++++---------- src/postprocessing/TAARenderPass.js | 100 ++- src/postprocessing/TexturePass.d.ts | 4 +- src/postprocessing/TexturePass.js | 52 +- src/postprocessing/UnrealBloomPass.js | 379 ++++++----- 16 files changed, 1121 insertions(+), 1128 deletions(-) create mode 100644 src/postprocessing/RenderPixelatedPass.d.ts diff --git a/src/index.ts b/src/index.ts index 048ee377..2ca26da5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -131,34 +131,34 @@ export * from './controls/TrackballControls' export * from './controls/OrbitControls' export * from './controls/ArcballControls' export * from './controls/FlyControls' -// export * from './postprocessing/LUTPass' -// export * from './postprocessing/ClearPass' -// export * from './postprocessing/GlitchPass' -// export * from './postprocessing/HalftonePass' -// export * from './postprocessing/SMAAPass' -// export * from './postprocessing/FilmPass' -// export * from './postprocessing/OutlinePass' -// export * from './postprocessing/SSAOPass' -// export * from './postprocessing/SavePass' -// export * from './postprocessing/BokehPass' -// export * from './postprocessing/Pass' -// export * from './postprocessing/TexturePass' -// export * from './postprocessing/AdaptiveToneMappingPass' -// export * from './postprocessing/UnrealBloomPass' -// export * from './postprocessing/CubeTexturePass' -// export * from './postprocessing/SAOPass' -// export * from './postprocessing/AfterimagePass' -// export * from './postprocessing/MaskPass' -// export * from './postprocessing/EffectComposer' -// export * from './postprocessing/DotScreenPass' -// export * from './postprocessing/SSRPass' -// export * from './postprocessing/TAARenderPass' -// export * from './postprocessing/ShaderPass' -// export * from './postprocessing/SSAARenderPass' -// export * from './postprocessing/RenderPass' -// export * from './postprocessing/RenderPixelatedPass' -// export * from './postprocessing/BloomPass' -// export * from './postprocessing/WaterPass' +export * from './postprocessing/LUTPass' +export * from './postprocessing/ClearPass' +export * from './postprocessing/GlitchPass' +export * from './postprocessing/HalftonePass' +export * from './postprocessing/SMAAPass' +export * from './postprocessing/FilmPass' +export * from './postprocessing/OutlinePass' +// export * from './postprocessing/SSAOPass' // +export * from './postprocessing/SavePass' +export * from './postprocessing/BokehPass' +export * from './postprocessing/Pass' +export * from './postprocessing/TexturePass' +export * from './postprocessing/AdaptiveToneMappingPass' +// export * from './postprocessing/UnrealBloomPass' // +export * from './postprocessing/CubeTexturePass' +// export * from './postprocessing/SAOPass' // +export * from './postprocessing/AfterimagePass' +export * from './postprocessing/MaskPass' +export * from './postprocessing/EffectComposer' +export * from './postprocessing/DotScreenPass' +// export * from './postprocessing/SSRPass' // +export * from './postprocessing/TAARenderPass' +export * from './postprocessing/ShaderPass' +export * from './postprocessing/SSAARenderPass' +export * from './postprocessing/RenderPass' +export * from './postprocessing/RenderPixelatedPass' +export * from './postprocessing/BloomPass' +export * from './postprocessing/WaterPass' export * from './webxr/ARButton' // export * from './webxr/OculusHandModel' // // export * from './webxr/OculusHandPointerModel' // diff --git a/src/postprocessing/AdaptiveToneMappingPass.d.ts b/src/postprocessing/AdaptiveToneMappingPass.d.ts index a3d2fa97..dd1cb1c1 100644 --- a/src/postprocessing/AdaptiveToneMappingPass.d.ts +++ b/src/postprocessing/AdaptiveToneMappingPass.d.ts @@ -1,6 +1,6 @@ import { WebGLRenderTarget, ShaderMaterial } from 'three' -import { Pass } from './Pass' +import { Pass, FullScreenQuad } from './Pass' export class AdaptiveToneMappingPass extends Pass { constructor(adaptive?: boolean, resolution?: number) @@ -16,7 +16,7 @@ export class AdaptiveToneMappingPass extends Pass { adaptLuminanceShader: object materialAdaptiveLum: ShaderMaterial materialToneMap: ShaderMaterial - fsQuad: object + fsQuad: FullScreenQuad reset(): void setAdaptive(adaptive: boolean): void diff --git a/src/postprocessing/AdaptiveToneMappingPass.js b/src/postprocessing/AdaptiveToneMappingPass.js index 4381a40d..7bf40f41 100644 --- a/src/postprocessing/AdaptiveToneMappingPass.js +++ b/src/postprocessing/AdaptiveToneMappingPass.js @@ -1,14 +1,12 @@ import { - LinearFilter, LinearMipmapLinearFilter, MeshBasicMaterial, NoBlending, - RGBAFormat, ShaderMaterial, UniformsUtils, WebGLRenderTarget, } from 'three' -import { Pass, FullScreenQuad } from '../postprocessing/Pass' +import { Pass, FullScreenQuad } from './Pass' import { CopyShader } from '../shaders/CopyShader' import { LuminosityShader } from '../shaders/LuminosityShader' import { ToneMapShader } from '../shaders/ToneMapShader' @@ -21,112 +19,103 @@ import { ToneMapShader } from '../shaders/ToneMapShader' * Full-screen tone-mapping shader based on http://www.graphics.cornell.edu/~jaf/publications/sig02_paper.pdf */ -var AdaptiveToneMappingPass = function (adaptive, resolution) { - this.resolution = resolution !== undefined ? resolution : 256 - this.needsInit = true - this.adaptive = adaptive !== undefined ? !!adaptive : true - - this.luminanceRT = null - this.previousLuminanceRT = null - this.currentLuminanceRT = null - - if (CopyShader === undefined) console.error('THREE.AdaptiveToneMappingPass relies on CopyShader') - - var copyShader = CopyShader - - this.copyUniforms = UniformsUtils.clone(copyShader.uniforms) - - this.materialCopy = new ShaderMaterial({ - uniforms: this.copyUniforms, - vertexShader: copyShader.vertexShader, - fragmentShader: copyShader.fragmentShader, - blending: NoBlending, - depthTest: false, - }) - - if (LuminosityShader === undefined) console.error('THREE.AdaptiveToneMappingPass relies on LuminosityShader') - - this.materialLuminance = new ShaderMaterial({ - uniforms: UniformsUtils.clone(LuminosityShader.uniforms), - vertexShader: LuminosityShader.vertexShader, - fragmentShader: LuminosityShader.fragmentShader, - blending: NoBlending, - }) - - this.adaptLuminanceShader = { - defines: { - MIP_LEVEL_1X1: (Math.log(this.resolution) / Math.log(2.0)).toFixed(1), - }, - uniforms: { - lastLum: { value: null }, - currentLum: { value: null }, - minLuminance: { value: 0.01 }, - delta: { value: 0.016 }, - tau: { value: 1.0 }, - }, - vertexShader: [ - 'varying vec2 vUv;', - - 'void main() {', - - ' vUv = uv;', - ' gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );', - - '}', - ].join('\n'), - fragmentShader: [ - 'varying vec2 vUv;', - - 'uniform sampler2D lastLum;', - 'uniform sampler2D currentLum;', - 'uniform float minLuminance;', - 'uniform float delta;', - 'uniform float tau;', - - 'void main() {', - - ' vec4 lastLum = texture2D( lastLum, vUv, MIP_LEVEL_1X1 );', - ' vec4 currentLum = texture2D( currentLum, vUv, MIP_LEVEL_1X1 );', - - ' float fLastLum = max( minLuminance, lastLum.r );', - ' float fCurrentLum = max( minLuminance, currentLum.r );', - - //The adaption seems to work better in extreme lighting differences - //if the input luminance is squared. - ' fCurrentLum *= fCurrentLum;', - - // Adapt the luminance using Pattanaik's technique - ' float fAdaptedLum = fLastLum + (fCurrentLum - fLastLum) * (1.0 - exp(-delta * tau));', - // "fAdaptedLum = sqrt(fAdaptedLum);", - ' gl_FragColor.r = fAdaptedLum;', - '}', - ].join('\n'), - } - - this.materialAdaptiveLum = new ShaderMaterial({ - uniforms: UniformsUtils.clone(this.adaptLuminanceShader.uniforms), - vertexShader: this.adaptLuminanceShader.vertexShader, - fragmentShader: this.adaptLuminanceShader.fragmentShader, - defines: Object.assign({}, this.adaptLuminanceShader.defines), - blending: NoBlending, - }) - - if (ToneMapShader === undefined) console.error('THREE.AdaptiveToneMappingPass relies on ToneMapShader') - - this.materialToneMap = new ShaderMaterial({ - uniforms: UniformsUtils.clone(ToneMapShader.uniforms), - vertexShader: ToneMapShader.vertexShader, - fragmentShader: ToneMapShader.fragmentShader, - blending: NoBlending, - }) - - this.fsQuad = new FullScreenQuad(null) -} +class AdaptiveToneMappingPass extends Pass { + constructor(adaptive, resolution) { + super() + + this.resolution = resolution !== undefined ? resolution : 256 + this.needsInit = true + this.adaptive = adaptive !== undefined ? !!adaptive : true + + this.luminanceRT = null + this.previousLuminanceRT = null + this.currentLuminanceRT = null + + const copyShader = CopyShader + + this.copyUniforms = UniformsUtils.clone(copyShader.uniforms) + + this.materialCopy = new ShaderMaterial({ + uniforms: this.copyUniforms, + vertexShader: copyShader.vertexShader, + fragmentShader: copyShader.fragmentShader, + blending: NoBlending, + depthTest: false, + }) + + this.materialLuminance = new ShaderMaterial({ + uniforms: UniformsUtils.clone(LuminosityShader.uniforms), + vertexShader: LuminosityShader.vertexShader, + fragmentShader: LuminosityShader.fragmentShader, + blending: NoBlending, + }) + + this.adaptLuminanceShader = { + defines: { + MIP_LEVEL_1X1: (Math.log(this.resolution) / Math.log(2.0)).toFixed(1), + }, + uniforms: { + lastLum: { value: null }, + currentLum: { value: null }, + minLuminance: { value: 0.01 }, + delta: { value: 0.016 }, + tau: { value: 1.0 }, + }, + vertexShader: `varying vec2 vUv; + + void main() { + + vUv = uv; + gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); + + }`, + + fragmentShader: `varying vec2 vUv; + + uniform sampler2D lastLum; + uniform sampler2D currentLum; + uniform float minLuminance; + uniform float delta; + uniform float tau; + + void main() { + + vec4 lastLum = texture2D( lastLum, vUv, MIP_LEVEL_1X1 ); + vec4 currentLum = texture2D( currentLum, vUv, MIP_LEVEL_1X1 ); + + float fLastLum = max( minLuminance, lastLum.r ); + float fCurrentLum = max( minLuminance, currentLum.r ); + + //The adaption seems to work better in extreme lighting differences + //if the input luminance is squared. + fCurrentLum *= fCurrentLum; + + // Adapt the luminance using Pattanaik's technique + float fAdaptedLum = fLastLum + (fCurrentLum - fLastLum) * (1.0 - exp(-delta * tau)); + // "fAdaptedLum = sqrt(fAdaptedLum); + gl_FragColor.r = fAdaptedLum; + }`, + } -AdaptiveToneMappingPass.prototype = Object.assign(Object.create(Pass.prototype), { - constructor: AdaptiveToneMappingPass, + this.materialAdaptiveLum = new ShaderMaterial({ + uniforms: UniformsUtils.clone(this.adaptLuminanceShader.uniforms), + vertexShader: this.adaptLuminanceShader.vertexShader, + fragmentShader: this.adaptLuminanceShader.fragmentShader, + defines: Object.assign({}, this.adaptLuminanceShader.defines), + blending: NoBlending, + }) + + this.materialToneMap = new ShaderMaterial({ + uniforms: UniformsUtils.clone(ToneMapShader.uniforms), + vertexShader: ToneMapShader.vertexShader, + fragmentShader: ToneMapShader.fragmentShader, + blending: NoBlending, + }) + + this.fsQuad = new FullScreenQuad(null) + } - render: function (renderer, writeBuffer, readBuffer, deltaTime /*, maskActive*/) { + render(renderer, writeBuffer, readBuffer, deltaTime /*, maskActive*/) { if (this.needsInit) { this.reset(renderer) @@ -172,9 +161,9 @@ AdaptiveToneMappingPass.prototype = Object.assign(Object.create(Pass.prototype), this.fsQuad.render(renderer) } - }, + } - reset: function () { + reset() { // render targets if (this.luminanceRT) { this.luminanceRT.dispose() @@ -188,23 +177,18 @@ AdaptiveToneMappingPass.prototype = Object.assign(Object.create(Pass.prototype), this.previousLuminanceRT.dispose() } - var pars = { - minFilter: LinearFilter, - magFilter: LinearFilter, - format: RGBAFormat, - } // was RGB format. changed to RGBA format. see discussion in #8415 / #8450 - - this.luminanceRT = new WebGLRenderTarget(this.resolution, this.resolution, pars) + this.luminanceRT = new WebGLRenderTarget(this.resolution, this.resolution) this.luminanceRT.texture.name = 'AdaptiveToneMappingPass.l' this.luminanceRT.texture.generateMipmaps = false - this.previousLuminanceRT = new WebGLRenderTarget(this.resolution, this.resolution, pars) + this.previousLuminanceRT = new WebGLRenderTarget(this.resolution, this.resolution) this.previousLuminanceRT.texture.name = 'AdaptiveToneMappingPass.pl' this.previousLuminanceRT.texture.generateMipmaps = false // We only need mipmapping for the current luminosity because we want a down-sampled version to sample in our adaptive shader - pars.minFilter = LinearMipmapLinearFilter - pars.generateMipmaps = true + + const pars = { minFilter: LinearMipmapLinearFilter, generateMipmaps: true } + this.currentLuminanceRT = new WebGLRenderTarget(this.resolution, this.resolution, pars) this.currentLuminanceRT.texture.name = 'AdaptiveToneMappingPass.cl' @@ -221,9 +205,9 @@ AdaptiveToneMappingPass.prototype = Object.assign(Object.create(Pass.prototype), // renderer.render( this.scene, this.camera, this.luminanceRT ); // renderer.render( this.scene, this.camera, this.previousLuminanceRT ); // renderer.render( this.scene, this.camera, this.currentLuminanceRT ); - }, + } - setAdaptive: function (adaptive) { + setAdaptive(adaptive) { if (adaptive) { this.adaptive = true this.materialToneMap.defines['ADAPTED_LUMINANCE'] = '' @@ -235,40 +219,40 @@ AdaptiveToneMappingPass.prototype = Object.assign(Object.create(Pass.prototype), } this.materialToneMap.needsUpdate = true - }, + } - setAdaptionRate: function (rate) { + setAdaptionRate(rate) { if (rate) { this.materialAdaptiveLum.uniforms.tau.value = Math.abs(rate) } - }, + } - setMinLuminance: function (minLum) { + setMinLuminance(minLum) { if (minLum) { this.materialToneMap.uniforms.minLuminance.value = minLum this.materialAdaptiveLum.uniforms.minLuminance.value = minLum } - }, + } - setMaxLuminance: function (maxLum) { + setMaxLuminance(maxLum) { if (maxLum) { this.materialToneMap.uniforms.maxLuminance.value = maxLum } - }, + } - setAverageLuminance: function (avgLum) { + setAverageLuminance(avgLum) { if (avgLum) { this.materialToneMap.uniforms.averageLuminance.value = avgLum } - }, + } - setMiddleGrey: function (middleGrey) { + setMiddleGrey(middleGrey) { if (middleGrey) { this.materialToneMap.uniforms.middleGrey.value = middleGrey } - }, + } - dispose: function () { + dispose() { if (this.luminanceRT) { this.luminanceRT.dispose() } @@ -296,7 +280,7 @@ AdaptiveToneMappingPass.prototype = Object.assign(Object.create(Pass.prototype), if (this.materialToneMap) { this.materialToneMap.dispose() } - }, -}) + } +} export { AdaptiveToneMappingPass } diff --git a/src/postprocessing/CubeTexturePass.js b/src/postprocessing/CubeTexturePass.js index 883e7598..4deaaa89 100644 --- a/src/postprocessing/CubeTexturePass.js +++ b/src/postprocessing/CubeTexturePass.js @@ -1,51 +1,51 @@ import { BackSide, BoxGeometry, Mesh, PerspectiveCamera, Scene, ShaderLib, ShaderMaterial, UniformsUtils } from 'three' -import { Pass } from '../postprocessing/Pass' - -var CubeTexturePass = function (camera, envMap, opacity) { - this.camera = camera - - this.needsSwap = false - - this.cubeShader = ShaderLib['cube'] - this.cubeMesh = new Mesh( - new BoxGeometry(10, 10, 10), - new ShaderMaterial({ - uniforms: UniformsUtils.clone(this.cubeShader.uniforms), - vertexShader: this.cubeShader.vertexShader, - fragmentShader: this.cubeShader.fragmentShader, - depthTest: false, - depthWrite: false, - side: BackSide, - }), - ) - - Object.defineProperty(this.cubeMesh.material, 'envMap', { - get: function () { - return this.uniforms.envMap.value - }, - }) - - this.envMap = envMap - this.opacity = opacity !== undefined ? opacity : 1.0 - - this.cubeScene = new Scene() - this.cubeCamera = new PerspectiveCamera() - this.cubeScene.add(this.cubeMesh) -} +import { Pass } from './Pass' + +class CubeTexturePass extends Pass { + constructor(camera, tCube, opacity = 1) { + super() + + this.camera = camera + + this.needsSwap = false + + this.cubeShader = ShaderLib['cube'] + this.cubeMesh = new Mesh( + new BoxGeometry(10, 10, 10), + new ShaderMaterial({ + uniforms: UniformsUtils.clone(this.cubeShader.uniforms), + vertexShader: this.cubeShader.vertexShader, + fragmentShader: this.cubeShader.fragmentShader, + depthTest: false, + depthWrite: false, + side: BackSide, + }), + ) -CubeTexturePass.prototype = Object.assign(Object.create(Pass.prototype), { - constructor: CubeTexturePass, + Object.defineProperty(this.cubeMesh.material, 'envMap', { + get: function () { + return this.uniforms.tCube.value + }, + }) - render: function (renderer, writeBuffer, readBuffer /*, deltaTime, maskActive*/) { - var oldAutoClear = renderer.autoClear + this.tCube = tCube + this.opacity = opacity + + this.cubeScene = new Scene() + this.cubeCamera = new PerspectiveCamera() + this.cubeScene.add(this.cubeMesh) + } + + render(renderer, writeBuffer, readBuffer /*, deltaTime, maskActive*/) { + const oldAutoClear = renderer.autoClear renderer.autoClear = false this.cubeCamera.projectionMatrix.copy(this.camera.projectionMatrix) this.cubeCamera.quaternion.setFromRotationMatrix(this.camera.matrixWorld) - this.cubeMesh.material.uniforms.envMap.value = this.envMap - this.cubeMesh.material.uniforms.flipEnvMap.value = - this.envMap.isCubeTexture && this.envMap._needsFlipEnvMap ? -1 : 1 + this.cubeMesh.material.uniforms.tCube.value = this.tCube + this.cubeMesh.material.uniforms.tFlip.value = + this.tCube.isCubeTexture && this.tCube.isRenderTargetTexture === false ? -1 : 1 this.cubeMesh.material.uniforms.opacity.value = this.opacity this.cubeMesh.material.transparent = this.opacity < 1.0 @@ -54,7 +54,12 @@ CubeTexturePass.prototype = Object.assign(Object.create(Pass.prototype), { renderer.render(this.cubeScene, this.cubeCamera) renderer.autoClear = oldAutoClear - }, -}) + } + + dispose() { + this.cubeMesh.geometry.dispose() + this.cubeMesh.material.dispose() + } +} export { CubeTexturePass } diff --git a/src/postprocessing/RenderPixelatedPass.d.ts b/src/postprocessing/RenderPixelatedPass.d.ts new file mode 100644 index 00000000..45ce00bf --- /dev/null +++ b/src/postprocessing/RenderPixelatedPass.d.ts @@ -0,0 +1,28 @@ +import { Scene, Camera, ShaderMaterial, Vector2, MeshNormalMaterial, WebGLRenderTarget } from 'three' + +import { Pass, FullScreenQuad } from './Pass' + +export interface RenderPixelatedPassParameters { + normalEdgeStrength?: number + depthEdgeStrength?: number +} + +export class RenderPixelatedPass extends Pass { + constructor(pixelSize: number, scene: Scene, camera: Camera, options?: RenderPixelatedPassParameters) + pixelSize: number + resolution: Vector2 + renderResolution: Vector2 + + pixelatedMaterial: ShaderMaterial + normalMaterial: MeshNormalMaterial + + fsQuad: FullScreenQuad + scene: Scene + camera: Camera + + normalEdgeStrength: RenderPixelatedPassParameters['normalEdgeStrength'] + depthEdgeStrength: RenderPixelatedPassParameters['depthEdgeStrength'] + + beautyRenderTarget: WebGLRenderTarget + normalRenderTarget: WebGLRenderTarget +} diff --git a/src/postprocessing/SAOPass.d.ts b/src/postprocessing/SAOPass.d.ts index 80ef8254..eb200639 100644 --- a/src/postprocessing/SAOPass.d.ts +++ b/src/postprocessing/SAOPass.d.ts @@ -12,7 +12,7 @@ import { ColorRepresentation, } from 'three' -import { Pass } from './Pass' +import { Pass, FullScreenQuad } from './Pass' export enum OUTPUT { Beauty, @@ -57,10 +57,10 @@ export class SAOPass extends Pass { hBlurMaterial: ShaderMaterial materialCopy: ShaderMaterial depthCopy: ShaderMaterial - fsQuad: object + fsQuad: FullScreenQuad params: SAOPassParams - static OUTPUT: OUTPUT + static OUTPUT: typeof OUTPUT renderPass( renderer: WebGLRenderer, diff --git a/src/postprocessing/SAOPass.js b/src/postprocessing/SAOPass.js index cc822315..6125d3b8 100644 --- a/src/postprocessing/SAOPass.js +++ b/src/postprocessing/SAOPass.js @@ -5,13 +5,12 @@ import { DepthTexture, DstAlphaFactor, DstColorFactor, - LinearFilter, + HalfFloatType, MeshDepthMaterial, MeshNormalMaterial, NearestFilter, NoBlending, RGBADepthPacking, - RGBAFormat, ShaderMaterial, UniformsUtils, UnsignedShortType, @@ -19,179 +18,161 @@ import { WebGLRenderTarget, ZeroFactor, } from 'three' -import { Pass, FullScreenQuad } from '../postprocessing/Pass' +import { Pass, FullScreenQuad } from './Pass' import { SAOShader } from '../shaders/SAOShader' -import { DepthLimitedBlurShader, BlurShaderUtils } from '../shaders/DepthLimitedBlurShader' +import { DepthLimitedBlurShader } from '../shaders/DepthLimitedBlurShader' +import { BlurShaderUtils } from '../shaders/DepthLimitedBlurShader' import { CopyShader } from '../shaders/CopyShader' import { UnpackDepthRGBAShader } from '../shaders/UnpackDepthRGBAShader' /** * SAO implementation inspired from bhouston previous SAO work */ - -var SAOPass = function (scene, camera, depthTexture, useNormals, resolution) { - this.scene = scene - this.camera = camera - - this.clear = true - this.needsSwap = false - - this.supportsDepthTextureExtension = depthTexture !== undefined ? depthTexture : false - this.supportsNormalTexture = useNormals !== undefined ? useNormals : false - - this.originalClearColor = new Color() - this._oldClearColor = new Color() - this.oldClearAlpha = 1 - - this.params = { - output: 0, - saoBias: 0.5, - saoIntensity: 0.18, - saoScale: 1, - saoKernelRadius: 100, - saoMinResolution: 0, - saoBlur: true, - saoBlurRadius: 8, - saoBlurStdDev: 4, - saoBlurDepthCutoff: 0.01, - } - - this.resolution = resolution !== undefined ? new Vector2(resolution.x, resolution.y) : new Vector2(256, 256) - - this.saoRenderTarget = new WebGLRenderTarget(this.resolution.x, this.resolution.y, { - minFilter: LinearFilter, - magFilter: LinearFilter, - format: RGBAFormat, - }) - this.blurIntermediateRenderTarget = this.saoRenderTarget.clone() - this.beautyRenderTarget = this.saoRenderTarget.clone() - - this.normalRenderTarget = new WebGLRenderTarget(this.resolution.x, this.resolution.y, { - minFilter: NearestFilter, - magFilter: NearestFilter, - format: RGBAFormat, - }) - this.depthRenderTarget = this.normalRenderTarget.clone() - - if (this.supportsDepthTextureExtension) { - var depthTexture = new DepthTexture() - depthTexture.type = UnsignedShortType - - this.beautyRenderTarget.depthTexture = depthTexture - this.beautyRenderTarget.depthBuffer = true +class SAOPass extends Pass { + static OUTPUT = { + Beauty: 1, + Default: 0, + SAO: 2, + Depth: 3, + Normal: 4, } - this.depthMaterial = new MeshDepthMaterial() - this.depthMaterial.depthPacking = RGBADepthPacking - this.depthMaterial.blending = NoBlending - - this.normalMaterial = new MeshNormalMaterial() - this.normalMaterial.blending = NoBlending - - if (SAOShader === undefined) { - console.error('THREE.SAOPass relies on SAOShader') - } + constructor(scene, camera, useDepthTexture = false, useNormals = false, resolution = new Vector2(256, 256)) { + super() + + this.scene = scene + this.camera = camera + + this.clear = true + this.needsSwap = false + + this.supportsDepthTextureExtension = useDepthTexture + this.supportsNormalTexture = useNormals + + this.originalClearColor = new Color() + this._oldClearColor = new Color() + this.oldClearAlpha = 1 + + this.params = { + output: 0, + saoBias: 0.5, + saoIntensity: 0.18, + saoScale: 1, + saoKernelRadius: 100, + saoMinResolution: 0, + saoBlur: true, + saoBlurRadius: 8, + saoBlurStdDev: 4, + saoBlurDepthCutoff: 0.01, + } - this.saoMaterial = new ShaderMaterial({ - defines: Object.assign({}, SAOShader.defines), - fragmentShader: SAOShader.fragmentShader, - vertexShader: SAOShader.vertexShader, - uniforms: UniformsUtils.clone(SAOShader.uniforms), - }) - this.saoMaterial.extensions.derivatives = true - this.saoMaterial.defines['DEPTH_PACKING'] = this.supportsDepthTextureExtension ? 0 : 1 - this.saoMaterial.defines['NORMAL_TEXTURE'] = this.supportsNormalTexture ? 1 : 0 - this.saoMaterial.defines['PERSPECTIVE_CAMERA'] = this.camera.isPerspectiveCamera ? 1 : 0 - this.saoMaterial.uniforms['tDepth'].value = this.supportsDepthTextureExtension - ? depthTexture - : this.depthRenderTarget.texture - this.saoMaterial.uniforms['tNormal'].value = this.normalRenderTarget.texture - this.saoMaterial.uniforms['size'].value.set(this.resolution.x, this.resolution.y) - this.saoMaterial.uniforms['cameraInverseProjectionMatrix'].value.copy(this.camera.projectionMatrixInverse) - this.saoMaterial.uniforms['cameraProjectionMatrix'].value = this.camera.projectionMatrix - this.saoMaterial.blending = NoBlending - - if (DepthLimitedBlurShader === undefined) { - console.error('THREE.SAOPass relies on DepthLimitedBlurShader') - } + this.resolution = new Vector2(resolution.x, resolution.y) - this.vBlurMaterial = new ShaderMaterial({ - uniforms: UniformsUtils.clone(DepthLimitedBlurShader.uniforms), - defines: Object.assign({}, DepthLimitedBlurShader.defines), - vertexShader: DepthLimitedBlurShader.vertexShader, - fragmentShader: DepthLimitedBlurShader.fragmentShader, - }) - this.vBlurMaterial.defines['DEPTH_PACKING'] = this.supportsDepthTextureExtension ? 0 : 1 - this.vBlurMaterial.defines['PERSPECTIVE_CAMERA'] = this.camera.isPerspectiveCamera ? 1 : 0 - this.vBlurMaterial.uniforms['tDiffuse'].value = this.saoRenderTarget.texture - this.vBlurMaterial.uniforms['tDepth'].value = this.supportsDepthTextureExtension - ? depthTexture - : this.depthRenderTarget.texture - this.vBlurMaterial.uniforms['size'].value.set(this.resolution.x, this.resolution.y) - this.vBlurMaterial.blending = NoBlending - - this.hBlurMaterial = new ShaderMaterial({ - uniforms: UniformsUtils.clone(DepthLimitedBlurShader.uniforms), - defines: Object.assign({}, DepthLimitedBlurShader.defines), - vertexShader: DepthLimitedBlurShader.vertexShader, - fragmentShader: DepthLimitedBlurShader.fragmentShader, - }) - this.hBlurMaterial.defines['DEPTH_PACKING'] = this.supportsDepthTextureExtension ? 0 : 1 - this.hBlurMaterial.defines['PERSPECTIVE_CAMERA'] = this.camera.isPerspectiveCamera ? 1 : 0 - this.hBlurMaterial.uniforms['tDiffuse'].value = this.blurIntermediateRenderTarget.texture - this.hBlurMaterial.uniforms['tDepth'].value = this.supportsDepthTextureExtension - ? depthTexture - : this.depthRenderTarget.texture - this.hBlurMaterial.uniforms['size'].value.set(this.resolution.x, this.resolution.y) - this.hBlurMaterial.blending = NoBlending - - if (CopyShader === undefined) { - console.error('THREE.SAOPass relies on CopyShader') - } + this.saoRenderTarget = new WebGLRenderTarget(this.resolution.x, this.resolution.y, { type: HalfFloatType }) + this.blurIntermediateRenderTarget = this.saoRenderTarget.clone() + this.beautyRenderTarget = this.saoRenderTarget.clone() - this.materialCopy = new ShaderMaterial({ - uniforms: UniformsUtils.clone(CopyShader.uniforms), - vertexShader: CopyShader.vertexShader, - fragmentShader: CopyShader.fragmentShader, - blending: NoBlending, - }) - this.materialCopy.transparent = true - this.materialCopy.depthTest = false - this.materialCopy.depthWrite = false - this.materialCopy.blending = CustomBlending - this.materialCopy.blendSrc = DstColorFactor - this.materialCopy.blendDst = ZeroFactor - this.materialCopy.blendEquation = AddEquation - this.materialCopy.blendSrcAlpha = DstAlphaFactor - this.materialCopy.blendDstAlpha = ZeroFactor - this.materialCopy.blendEquationAlpha = AddEquation - - if (UnpackDepthRGBAShader === undefined) { - console.error('THREE.SAOPass relies on UnpackDepthRGBAShader') - } + this.normalRenderTarget = new WebGLRenderTarget(this.resolution.x, this.resolution.y, { + minFilter: NearestFilter, + magFilter: NearestFilter, + type: HalfFloatType, + }) + this.depthRenderTarget = this.normalRenderTarget.clone() - this.depthCopy = new ShaderMaterial({ - uniforms: UniformsUtils.clone(UnpackDepthRGBAShader.uniforms), - vertexShader: UnpackDepthRGBAShader.vertexShader, - fragmentShader: UnpackDepthRGBAShader.fragmentShader, - blending: NoBlending, - }) + let depthTexture - this.fsQuad = new FullScreenQuad(null) -} + if (this.supportsDepthTextureExtension) { + depthTexture = new DepthTexture() + depthTexture.type = UnsignedShortType -SAOPass.OUTPUT = { - Beauty: 1, - Default: 0, - SAO: 2, - Depth: 3, - Normal: 4, -} + this.beautyRenderTarget.depthTexture = depthTexture + this.beautyRenderTarget.depthBuffer = true + } -SAOPass.prototype = Object.assign(Object.create(Pass.prototype), { - constructor: SAOPass, + this.depthMaterial = new MeshDepthMaterial() + this.depthMaterial.depthPacking = RGBADepthPacking + this.depthMaterial.blending = NoBlending + + this.normalMaterial = new MeshNormalMaterial() + this.normalMaterial.blending = NoBlending + + this.saoMaterial = new ShaderMaterial({ + defines: Object.assign({}, SAOShader.defines), + fragmentShader: SAOShader.fragmentShader, + vertexShader: SAOShader.vertexShader, + uniforms: UniformsUtils.clone(SAOShader.uniforms), + }) + this.saoMaterial.extensions.derivatives = true + this.saoMaterial.defines['DEPTH_PACKING'] = this.supportsDepthTextureExtension ? 0 : 1 + this.saoMaterial.defines['NORMAL_TEXTURE'] = this.supportsNormalTexture ? 1 : 0 + this.saoMaterial.defines['PERSPECTIVE_CAMERA'] = this.camera.isPerspectiveCamera ? 1 : 0 + this.saoMaterial.uniforms['tDepth'].value = this.supportsDepthTextureExtension + ? depthTexture + : this.depthRenderTarget.texture + this.saoMaterial.uniforms['tNormal'].value = this.normalRenderTarget.texture + this.saoMaterial.uniforms['size'].value.set(this.resolution.x, this.resolution.y) + this.saoMaterial.uniforms['cameraInverseProjectionMatrix'].value.copy(this.camera.projectionMatrixInverse) + this.saoMaterial.uniforms['cameraProjectionMatrix'].value = this.camera.projectionMatrix + this.saoMaterial.blending = NoBlending + + this.vBlurMaterial = new ShaderMaterial({ + uniforms: UniformsUtils.clone(DepthLimitedBlurShader.uniforms), + defines: Object.assign({}, DepthLimitedBlurShader.defines), + vertexShader: DepthLimitedBlurShader.vertexShader, + fragmentShader: DepthLimitedBlurShader.fragmentShader, + }) + this.vBlurMaterial.defines['DEPTH_PACKING'] = this.supportsDepthTextureExtension ? 0 : 1 + this.vBlurMaterial.defines['PERSPECTIVE_CAMERA'] = this.camera.isPerspectiveCamera ? 1 : 0 + this.vBlurMaterial.uniforms['tDiffuse'].value = this.saoRenderTarget.texture + this.vBlurMaterial.uniforms['tDepth'].value = this.supportsDepthTextureExtension + ? depthTexture + : this.depthRenderTarget.texture + this.vBlurMaterial.uniforms['size'].value.set(this.resolution.x, this.resolution.y) + this.vBlurMaterial.blending = NoBlending + + this.hBlurMaterial = new ShaderMaterial({ + uniforms: UniformsUtils.clone(DepthLimitedBlurShader.uniforms), + defines: Object.assign({}, DepthLimitedBlurShader.defines), + vertexShader: DepthLimitedBlurShader.vertexShader, + fragmentShader: DepthLimitedBlurShader.fragmentShader, + }) + this.hBlurMaterial.defines['DEPTH_PACKING'] = this.supportsDepthTextureExtension ? 0 : 1 + this.hBlurMaterial.defines['PERSPECTIVE_CAMERA'] = this.camera.isPerspectiveCamera ? 1 : 0 + this.hBlurMaterial.uniforms['tDiffuse'].value = this.blurIntermediateRenderTarget.texture + this.hBlurMaterial.uniforms['tDepth'].value = this.supportsDepthTextureExtension + ? depthTexture + : this.depthRenderTarget.texture + this.hBlurMaterial.uniforms['size'].value.set(this.resolution.x, this.resolution.y) + this.hBlurMaterial.blending = NoBlending + + this.materialCopy = new ShaderMaterial({ + uniforms: UniformsUtils.clone(CopyShader.uniforms), + vertexShader: CopyShader.vertexShader, + fragmentShader: CopyShader.fragmentShader, + blending: NoBlending, + }) + this.materialCopy.transparent = true + this.materialCopy.depthTest = false + this.materialCopy.depthWrite = false + this.materialCopy.blending = CustomBlending + this.materialCopy.blendSrc = DstColorFactor + this.materialCopy.blendDst = ZeroFactor + this.materialCopy.blendEquation = AddEquation + this.materialCopy.blendSrcAlpha = DstAlphaFactor + this.materialCopy.blendDstAlpha = ZeroFactor + this.materialCopy.blendEquationAlpha = AddEquation + + this.depthCopy = new ShaderMaterial({ + uniforms: UniformsUtils.clone(UnpackDepthRGBAShader.uniforms), + vertexShader: UnpackDepthRGBAShader.vertexShader, + fragmentShader: UnpackDepthRGBAShader.fragmentShader, + blending: NoBlending, + }) + + this.fsQuad = new FullScreenQuad(null) + } - render: function (renderer, writeBuffer, readBuffer /*, deltaTime, maskActive*/) { + render(renderer, writeBuffer, readBuffer /*, deltaTime, maskActive*/) { // Rendering readBuffer first when rendering to screen if (this.renderToScreen) { this.materialCopy.blending = NoBlending @@ -206,7 +187,7 @@ SAOPass.prototype = Object.assign(Object.create(Pass.prototype), { renderer.getClearColor(this._oldClearColor) this.oldClearAlpha = renderer.getClearAlpha() - var oldAutoClear = renderer.autoClear + const oldAutoClear = renderer.autoClear renderer.autoClear = false renderer.setRenderTarget(this.depthRenderTarget) @@ -221,7 +202,7 @@ SAOPass.prototype = Object.assign(Object.create(Pass.prototype), { this.saoMaterial.uniforms['cameraFar'].value = this.camera.far // this.saoMaterial.uniforms['randomSeed'].value = Math.random(); - var depthCutoff = this.params.saoBlurDepthCutoff * (this.camera.far - this.camera.near) + const depthCutoff = this.params.saoBlurDepthCutoff * (this.camera.far - this.camera.near) this.vBlurMaterial.uniforms['depthCutoff'].value = depthCutoff this.hBlurMaterial.uniforms['depthCutoff'].value = depthCutoff @@ -274,7 +255,7 @@ SAOPass.prototype = Object.assign(Object.create(Pass.prototype), { this.renderPass(renderer, this.hBlurMaterial, this.saoRenderTarget, 0xffffff, 1.0) } - var outputMaterial = this.materialCopy + let outputMaterial = this.materialCopy // Setting up SAO rendering if (this.params.output === 3) { if (this.supportsDepthTextureExtension) { @@ -305,13 +286,13 @@ SAOPass.prototype = Object.assign(Object.create(Pass.prototype), { renderer.setClearColor(this._oldClearColor, this.oldClearAlpha) renderer.autoClear = oldAutoClear - }, + } - renderPass: function (renderer, passMaterial, renderTarget, clearColor, clearAlpha) { + renderPass(renderer, passMaterial, renderTarget, clearColor, clearAlpha) { // save original state renderer.getClearColor(this.originalClearColor) - var originalClearAlpha = renderer.getClearAlpha() - var originalAutoClear = renderer.autoClear + const originalClearAlpha = renderer.getClearAlpha() + const originalAutoClear = renderer.autoClear renderer.setRenderTarget(renderTarget) @@ -330,12 +311,12 @@ SAOPass.prototype = Object.assign(Object.create(Pass.prototype), { renderer.autoClear = originalAutoClear renderer.setClearColor(this.originalClearColor) renderer.setClearAlpha(originalClearAlpha) - }, + } - renderOverride: function (renderer, overrideMaterial, renderTarget, clearColor, clearAlpha) { + renderOverride(renderer, overrideMaterial, renderTarget, clearColor, clearAlpha) { renderer.getClearColor(this.originalClearColor) - var originalClearAlpha = renderer.getClearAlpha() - var originalAutoClear = renderer.autoClear + const originalClearAlpha = renderer.getClearAlpha() + const originalAutoClear = renderer.autoClear renderer.setRenderTarget(renderTarget) renderer.autoClear = false @@ -356,9 +337,9 @@ SAOPass.prototype = Object.assign(Object.create(Pass.prototype), { renderer.autoClear = originalAutoClear renderer.setClearColor(this.originalClearColor) renderer.setClearAlpha(originalClearAlpha) - }, + } - setSize: function (width, height) { + setSize(width, height) { this.beautyRenderTarget.setSize(width, height) this.saoRenderTarget.setSize(width, height) this.blurIntermediateRenderTarget.setSize(width, height) @@ -375,7 +356,25 @@ SAOPass.prototype = Object.assign(Object.create(Pass.prototype), { this.hBlurMaterial.uniforms['size'].value.set(width, height) this.hBlurMaterial.needsUpdate = true - }, -}) + } + + dispose() { + this.saoRenderTarget.dispose() + this.blurIntermediateRenderTarget.dispose() + this.beautyRenderTarget.dispose() + this.normalRenderTarget.dispose() + this.depthRenderTarget.dispose() + + this.depthMaterial.dispose() + this.normalMaterial.dispose() + this.saoMaterial.dispose() + this.vBlurMaterial.dispose() + this.hBlurMaterial.dispose() + this.materialCopy.dispose() + this.depthCopy.dispose() + + this.fsQuad.dispose() + } +} export { SAOPass } diff --git a/src/postprocessing/SSAARenderPass.d.ts b/src/postprocessing/SSAARenderPass.d.ts index 02532ca4..5b00754b 100644 --- a/src/postprocessing/SSAARenderPass.d.ts +++ b/src/postprocessing/SSAARenderPass.d.ts @@ -1,6 +1,6 @@ import { Scene, Camera, ColorRepresentation, ShaderMaterial, WebGLRenderTarget } from 'three' -import { Pass } from './Pass' +import { Pass, FullScreenQuad } from './Pass' export class SSAARenderPass extends Pass { constructor(scene: Scene, camera: Camera, clearColor?: ColorRepresentation, clearAlpha?: number) @@ -12,6 +12,6 @@ export class SSAARenderPass extends Pass { clearAlpha: number copyUniforms: object copyMaterial: ShaderMaterial - fsQuad: object + fsQuad: FullScreenQuad sampleRenderTarget: undefined | WebGLRenderTarget } diff --git a/src/postprocessing/SSAARenderPass.js b/src/postprocessing/SSAARenderPass.js index dec46823..744db7b3 100644 --- a/src/postprocessing/SSAARenderPass.js +++ b/src/postprocessing/SSAARenderPass.js @@ -1,13 +1,15 @@ import { - AdditiveBlending, + CustomBlending, + OneFactor, + AddEquation, + SrcAlphaFactor, Color, - LinearFilter, - RGBAFormat, + HalfFloatType, ShaderMaterial, UniformsUtils, WebGLRenderTarget, } from 'three' -import { Pass, FullScreenQuad } from '../postprocessing/Pass' +import { Pass, FullScreenQuad } from './Pass' import { CopyShader } from '../shaders/CopyShader' /** @@ -20,99 +22,115 @@ import { CopyShader } from '../shaders/CopyShader' * */ -var SSAARenderPass = function (scene, camera, clearColor, clearAlpha) { - this.scene = scene - this.camera = camera - - this.sampleLevel = 4 // specified as n, where the number of samples is 2^n, so sampleLevel = 4, is 2^4 samples, 16. - this.unbiased = true - - // as we need to clear the buffer in this pass, clearColor must be set to something, defaults to black. - this.clearColor = clearColor !== undefined ? clearColor : 0x000000 - this.clearAlpha = clearAlpha !== undefined ? clearAlpha : 0 - this._oldClearColor = new Color() - - if (CopyShader === undefined) console.error('THREE.SSAARenderPass relies on CopyShader') - - var copyShader = CopyShader - this.copyUniforms = UniformsUtils.clone(copyShader.uniforms) - - this.copyMaterial = new ShaderMaterial({ - uniforms: this.copyUniforms, - vertexShader: copyShader.vertexShader, - fragmentShader: copyShader.fragmentShader, - premultipliedAlpha: true, - transparent: true, - blending: AdditiveBlending, - depthTest: false, - depthWrite: false, - }) - - this.fsQuad = new FullScreenQuad(this.copyMaterial) -} - -SSAARenderPass.prototype = Object.assign(Object.create(Pass.prototype), { - constructor: SSAARenderPass, - - dispose: function () { +class SSAARenderPass extends Pass { + constructor(scene, camera, clearColor, clearAlpha) { + super() + + this.scene = scene + this.camera = camera + + this.sampleLevel = 4 // specified as n, where the number of samples is 2^n, so sampleLevel = 4, is 2^4 samples, 16. + this.unbiased = true + + // as we need to clear the buffer in this pass, clearColor must be set to something, defaults to black. + this.clearColor = clearColor !== undefined ? clearColor : 0x000000 + this.clearAlpha = clearAlpha !== undefined ? clearAlpha : 0 + this._oldClearColor = new Color() + + const copyShader = CopyShader + this.copyUniforms = UniformsUtils.clone(copyShader.uniforms) + + this.copyMaterial = new ShaderMaterial({ + uniforms: this.copyUniforms, + vertexShader: copyShader.vertexShader, + fragmentShader: copyShader.fragmentShader, + transparent: true, + depthTest: false, + depthWrite: false, + + // do not use AdditiveBlending because it mixes the alpha channel instead of adding + blending: CustomBlending, + blendEquation: AddEquation, + blendDst: OneFactor, + blendDstAlpha: OneFactor, + blendSrc: SrcAlphaFactor, + blendSrcAlpha: OneFactor, + }) + + this.fsQuad = new FullScreenQuad(this.copyMaterial) + } + + dispose() { if (this.sampleRenderTarget) { this.sampleRenderTarget.dispose() this.sampleRenderTarget = null } - }, - setSize: function (width, height) { + this.copyMaterial.dispose() + + this.fsQuad.dispose() + } + + setSize(width, height) { if (this.sampleRenderTarget) this.sampleRenderTarget.setSize(width, height) - }, + } - render: function (renderer, writeBuffer, readBuffer) { + render(renderer, writeBuffer, readBuffer) { if (!this.sampleRenderTarget) { - this.sampleRenderTarget = new WebGLRenderTarget(readBuffer.width, readBuffer.height, { - minFilter: LinearFilter, - magFilter: LinearFilter, - format: RGBAFormat, - }) + this.sampleRenderTarget = new WebGLRenderTarget(readBuffer.width, readBuffer.height, { type: HalfFloatType }) this.sampleRenderTarget.texture.name = 'SSAARenderPass.sample' } - var jitterOffsets = SSAARenderPass.JitterVectors[Math.max(0, Math.min(this.sampleLevel, 5))] + const jitterOffsets = _JitterVectors[Math.max(0, Math.min(this.sampleLevel, 5))] - var autoClear = renderer.autoClear + const autoClear = renderer.autoClear renderer.autoClear = false renderer.getClearColor(this._oldClearColor) - var oldClearAlpha = renderer.getClearAlpha() + const oldClearAlpha = renderer.getClearAlpha() - var baseSampleWeight = 1.0 / jitterOffsets.length - var roundingRange = 1 / 32 + const baseSampleWeight = 1.0 / jitterOffsets.length + const roundingRange = 1 / 32 this.copyUniforms['tDiffuse'].value = this.sampleRenderTarget.texture - var width = readBuffer.width, - height = readBuffer.height + const viewOffset = { + fullWidth: readBuffer.width, + fullHeight: readBuffer.height, + offsetX: 0, + offsetY: 0, + width: readBuffer.width, + height: readBuffer.height, + } + + const originalViewOffset = Object.assign({}, this.camera.view) + + if (originalViewOffset.enabled) Object.assign(viewOffset, originalViewOffset) // render the scene multiple times, each slightly jitter offset from the last and accumulate the results. for (let i = 0; i < jitterOffsets.length; i++) { - var jitterOffset = jitterOffsets[i] + const jitterOffset = jitterOffsets[i] if (this.camera.setViewOffset) { this.camera.setViewOffset( - width, - height, - jitterOffset[0] * 0.0625, - jitterOffset[1] * 0.0625, // 0.0625 = 1 / 16 - width, - height, + viewOffset.fullWidth, + viewOffset.fullHeight, + + viewOffset.offsetX + jitterOffset[0] * 0.0625, + viewOffset.offsetY + jitterOffset[1] * 0.0625, // 0.0625 = 1 / 16 + + viewOffset.width, + viewOffset.height, ) } - var sampleWeight = baseSampleWeight + let sampleWeight = baseSampleWeight if (this.unbiased) { // the theory is that equal weights for each sample lead to an accumulation of rounding errors. // The following equation varies the sampleWeight per sample so that it is uniformly distributed // across a range of values whose rounding errors cancel each other out. - var uniformCenteredDistribution = -0.5 + (i + 0.5) / jitterOffsets.length + const uniformCenteredDistribution = -0.5 + (i + 0.5) / jitterOffsets.length sampleWeight += roundingRange * uniformCenteredDistribution } @@ -132,92 +150,62 @@ SSAARenderPass.prototype = Object.assign(Object.create(Pass.prototype), { this.fsQuad.render(renderer) } - if (this.camera.clearViewOffset) this.camera.clearViewOffset() + if (this.camera.setViewOffset && originalViewOffset.enabled) { + this.camera.setViewOffset( + originalViewOffset.fullWidth, + originalViewOffset.fullHeight, + + originalViewOffset.offsetX, + originalViewOffset.offsetY, + + originalViewOffset.width, + originalViewOffset.height, + ) + } else if (this.camera.clearViewOffset) { + this.camera.clearViewOffset() + } renderer.autoClear = autoClear renderer.setClearColor(this._oldClearColor, oldClearAlpha) - }, -}) + } +} // These jitter vectors are specified in integers because it is easier. // I am assuming a [-8,8) integer grid, but it needs to be mapped onto [-0.5,0.5) // before being used, thus these integers need to be scaled by 1/16. // // Sample patterns reference: https://msdn.microsoft.com/en-us/library/windows/desktop/ff476218%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396 -SSAARenderPass.JitterVectors = [ - [[0, 0]], - [ - [4, 4], - [-4, -4], - ], - [ - [-2, -6], - [6, -2], - [-6, 2], - [2, 6], - ], - [ - [1, -3], - [-1, 3], - [5, 1], - [-3, -5], - [-5, 5], - [-7, -1], - [3, 7], - [7, -7], - ], - [ - [1, 1], - [-1, -3], - [-3, 2], - [4, -1], - [-5, -2], - [2, 5], - [5, 3], - [3, -5], - [-2, 6], - [0, -7], - [-4, -6], - [-6, 4], - [-8, 0], - [7, -4], - [6, 7], - [-7, -8], - ], - [ - [-4, -7], - [-7, -5], - [-3, -5], - [-5, -4], - [-1, -4], - [-2, -2], - [-6, -1], - [-4, 0], - [-7, 1], - [-1, 2], - [-6, 3], - [-3, 3], - [-7, 6], - [-3, 6], - [-5, 7], - [-1, 7], - [5, -7], - [1, -6], - [6, -5], - [4, -4], - [2, -3], - [7, -2], - [1, -1], - [4, -1], - [2, 1], - [6, 2], - [0, 4], - [4, 4], - [2, 5], - [7, 5], - [5, 6], - [3, 7], - ], -] +// prettier-ignore +const _JitterVectors = [ + [ + [ 0, 0 ] + ], + [ + [ 4, 4 ], [ - 4, - 4 ] + ], + [ + [ - 2, - 6 ], [ 6, - 2 ], [ - 6, 2 ], [ 2, 6 ] + ], + [ + [ 1, - 3 ], [ - 1, 3 ], [ 5, 1 ], [ - 3, - 5 ], + [ - 5, 5 ], [ - 7, - 1 ], [ 3, 7 ], [ 7, - 7 ] + ], + [ + [ 1, 1 ], [ - 1, - 3 ], [ - 3, 2 ], [ 4, - 1 ], + [ - 5, - 2 ], [ 2, 5 ], [ 5, 3 ], [ 3, - 5 ], + [ - 2, 6 ], [ 0, - 7 ], [ - 4, - 6 ], [ - 6, 4 ], + [ - 8, 0 ], [ 7, - 4 ], [ 6, 7 ], [ - 7, - 8 ] + ], + [ + [ - 4, - 7 ], [ - 7, - 5 ], [ - 3, - 5 ], [ - 5, - 4 ], + [ - 1, - 4 ], [ - 2, - 2 ], [ - 6, - 1 ], [ - 4, 0 ], + [ - 7, 1 ], [ - 1, 2 ], [ - 6, 3 ], [ - 3, 3 ], + [ - 7, 6 ], [ - 3, 6 ], [ - 5, 7 ], [ - 1, 7 ], + [ 5, - 7 ], [ 1, - 6 ], [ 6, - 5 ], [ 4, - 4 ], + [ 2, - 3 ], [ 7, - 2 ], [ 1, - 1 ], [ 4, - 1 ], + [ 2, 1 ], [ 6, 2 ], [ 0, 4 ], [ 4, 4 ], + [ 2, 5 ], [ 7, 5 ], [ 5, 6 ], [ 3, 7 ] + ] +]; export { SSAARenderPass } diff --git a/src/postprocessing/SSAOPass.d.ts b/src/postprocessing/SSAOPass.d.ts index cf5fd35c..293d54f6 100644 --- a/src/postprocessing/SSAOPass.d.ts +++ b/src/postprocessing/SSAOPass.d.ts @@ -12,7 +12,7 @@ import { ColorRepresentation, } from 'three' -import { Pass } from './Pass' +import { Pass, FullScreenQuad } from './Pass' export enum SSAOPassOUTPUT { Default, @@ -46,7 +46,7 @@ export class SSAOPass extends Pass { blurMaterial: ShaderMaterial depthRenderMaterial: ShaderMaterial copyMaterial: ShaderMaterial - fsQuad: object + fsQuad: FullScreenQuad originalClearColor: Color static OUTPUT: SSAOPassOUTPUT diff --git a/src/postprocessing/SSAOPass.js b/src/postprocessing/SSAOPass.js index 8a9bfb91..52a5d0ed 100644 --- a/src/postprocessing/SSAOPass.js +++ b/src/postprocessing/SSAOPass.js @@ -29,6 +29,15 @@ import { SSAOShader, SSAOBlurShader, SSAODepthShader } from '../shaders/SSAOShad import { CopyShader } from '../shaders/CopyShader' class SSAOPass extends Pass { + static OUTPUT = { + Default: 0, + SSAO: 1, + Blur: 2, + Beauty: 3, + Depth: 4, + Normal: 5, + } + constructor(scene, camera, width, height) { super() @@ -392,13 +401,4 @@ class SSAOPass extends Pass { } } -SSAOPass.OUTPUT = { - Default: 0, - SSAO: 1, - Blur: 2, - Beauty: 3, - Depth: 4, - Normal: 5, -} - export { SSAOPass } diff --git a/src/postprocessing/SSRPass.js b/src/postprocessing/SSRPass.js index 15144fce..c46038c5 100644 --- a/src/postprocessing/SSRPass.js +++ b/src/postprocessing/SSRPass.js @@ -5,323 +5,295 @@ import { DepthTexture, SrcAlphaFactor, OneMinusSrcAlphaFactor, - LinearFilter, MeshNormalMaterial, MeshBasicMaterial, NearestFilter, NoBlending, - RGBAFormat, ShaderMaterial, UniformsUtils, UnsignedShortType, WebGLRenderTarget, HalfFloatType, } from 'three' -import { Pass, FullScreenQuad } from '../postprocessing/Pass' -import { SSRShader, SSRBlurShader, SSRDepthShader } from '../shaders/SSRShader' +import { Pass, FullScreenQuad } from './Pass' +import { SSRShader } from '../shaders/SSRShader' +import { SSRBlurShader } from '../shaders/SSRShader' +import { SSRDepthShader } from '../shaders/SSRShader' import { CopyShader } from '../shaders/CopyShader' -var SSRPass = function ({ - renderer, - scene, - camera, - width, - height, - selects, - encoding, - isPerspectiveCamera = true, - isBouncing = false, - morphTargets = false, - groundReflector, -}) { - this.width = width !== undefined ? width : 512 - this.height = height !== undefined ? height : 512 - - this.clear = true - - this.renderer = renderer - this.scene = scene - this.camera = camera - this.groundReflector = groundReflector - - this.opacity = SSRShader.uniforms.opacity.value - this.output = 0 - - this.maxDistance = SSRShader.uniforms.maxDistance.value - this.surfDist = SSRShader.uniforms.surfDist.value - - this.encoding = encoding - - this.tempColor = new Color() - - this._selects = selects - this.isSelective = Array.isArray(this._selects) - Object.defineProperty(this, 'selects', { - get() { - return this._selects - }, - set(val) { - if (this._selects === val) return - this._selects = val - if (Array.isArray(val)) { - this.isSelective = true - this.ssrMaterial.defines.isSelective = true +class SSRPass extends Pass { + static OUTPUT = { + Default: 0, + SSR: 1, + Beauty: 3, + Depth: 4, + Normal: 5, + Metalness: 7, + } + constructor({ renderer, scene, camera, width, height, selects, bouncing = false, groundReflector }) { + super() + + this.width = width !== undefined ? width : 512 + this.height = height !== undefined ? height : 512 + + this.clear = true + + this.renderer = renderer + this.scene = scene + this.camera = camera + this.groundReflector = groundReflector + + this.opacity = SSRShader.uniforms.opacity.value + this.output = 0 + + this.maxDistance = SSRShader.uniforms.maxDistance.value + this.thickness = SSRShader.uniforms.thickness.value + + this.tempColor = new Color() + + this._selects = selects + this.selective = Array.isArray(this._selects) + Object.defineProperty(this, 'selects', { + get() { + return this._selects + }, + set(val) { + if (this._selects === val) return + this._selects = val + if (Array.isArray(val)) { + this.selective = true + this.ssrMaterial.defines.SELECTIVE = true + this.ssrMaterial.needsUpdate = true + } else { + this.selective = false + this.ssrMaterial.defines.SELECTIVE = false + this.ssrMaterial.needsUpdate = true + } + }, + }) + + this._bouncing = bouncing + Object.defineProperty(this, 'bouncing', { + get() { + return this._bouncing + }, + set(val) { + if (this._bouncing === val) return + this._bouncing = val + if (val) { + this.ssrMaterial.uniforms['tDiffuse'].value = this.prevRenderTarget.texture + } else { + this.ssrMaterial.uniforms['tDiffuse'].value = this.beautyRenderTarget.texture + } + }, + }) + + this.blur = true + + this._distanceAttenuation = SSRShader.defines.DISTANCE_ATTENUATION + Object.defineProperty(this, 'distanceAttenuation', { + get() { + return this._distanceAttenuation + }, + set(val) { + if (this._distanceAttenuation === val) return + this._distanceAttenuation = val + this.ssrMaterial.defines.DISTANCE_ATTENUATION = val this.ssrMaterial.needsUpdate = true - } else { - this.isSelective = false - this.ssrMaterial.defines.isSelective = false + }, + }) + + this._fresnel = SSRShader.defines.FRESNEL + Object.defineProperty(this, 'fresnel', { + get() { + return this._fresnel + }, + set(val) { + if (this._fresnel === val) return + this._fresnel = val + this.ssrMaterial.defines.FRESNEL = val this.ssrMaterial.needsUpdate = true - } - }, - }) - - this._isBouncing = isBouncing ///todo: don't need defineProperty - Object.defineProperty(this, 'isBouncing', { - get() { - return this._isBouncing - }, - set(val) { - if (this._isBouncing === val) return - this._isBouncing = val - if (val) { - this.ssrMaterial.uniforms['tDiffuse'].value = this.prevRenderTarget.texture - } else { - this.ssrMaterial.uniforms['tDiffuse'].value = this.beautyRenderTarget.texture - } - }, - }) - - this.isBlur = true - - this._isDistanceAttenuation = SSRShader.defines.isDistanceAttenuation - Object.defineProperty(this, 'isDistanceAttenuation', { - get() { - return this._isDistanceAttenuation - }, - set(val) { - if (this._isDistanceAttenuation === val) return - this._isDistanceAttenuation = val - this.ssrMaterial.defines.isDistanceAttenuation = val - this.ssrMaterial.needsUpdate = true - }, - }) - - this._isFresnel = SSRShader.defines.isFresnel - Object.defineProperty(this, 'isFresnel', { - get() { - return this._isFresnel - }, - set(val) { - if (this._isFresnel === val) return - this._isFresnel = val - this.ssrMaterial.defines.isFresnel = val - this.ssrMaterial.needsUpdate = true - }, - }) - - this._isInfiniteThick = SSRShader.defines.isInfiniteThick - Object.defineProperty(this, 'isInfiniteThick', { - get() { - return this._isInfiniteThick - }, - set(val) { - if (this._isInfiniteThick === val) return - this._isInfiniteThick = val - this.ssrMaterial.defines.isInfiniteThick = val - this.ssrMaterial.needsUpdate = true - }, - }) - this.thickTolerance = SSRShader.uniforms.thickTolerance.value - - // beauty render target with depth buffer - - var depthTexture = new DepthTexture() - depthTexture.type = UnsignedShortType - depthTexture.minFilter = NearestFilter - depthTexture.maxFilter = NearestFilter - - this.beautyRenderTarget = new WebGLRenderTarget(this.width, this.height, { - minFilter: LinearFilter, - magFilter: LinearFilter, - format: RGBAFormat, - depthTexture: depthTexture, - depthBuffer: true, - }) - - //for bouncing - this.prevRenderTarget = new WebGLRenderTarget(this.width, this.height, { - minFilter: LinearFilter, - magFilter: LinearFilter, - format: RGBAFormat, - }) - - // normal render target - - this.normalRenderTarget = new WebGLRenderTarget(this.width, this.height, { - minFilter: NearestFilter, - magFilter: NearestFilter, - format: RGBAFormat, - type: HalfFloatType, - }) - - // metalness render target - - // if (this.isSelective) { - this.metalnessRenderTarget = new WebGLRenderTarget(this.width, this.height, { - minFilter: NearestFilter, - magFilter: NearestFilter, - format: RGBAFormat, - }) - // } - - // ssr render target - - this.ssrRenderTarget = new WebGLRenderTarget(this.width, this.height, { - minFilter: LinearFilter, - magFilter: LinearFilter, - format: RGBAFormat, - }) - - this.blurRenderTarget = this.ssrRenderTarget.clone() - this.blurRenderTarget2 = this.ssrRenderTarget.clone() - // this.blurRenderTarget3 = this.ssrRenderTarget.clone(); - - // ssr material - - if (SSRShader === undefined) { - console.error('THREE.SSRPass: The pass relies on SSRShader.') - } + }, + }) - this.ssrMaterial = new ShaderMaterial({ - defines: Object.assign( - { - MAX_STEP: Math.sqrt(window.innerWidth * window.innerWidth + window.innerHeight * window.innerHeight), + this._infiniteThick = SSRShader.defines.INFINITE_THICK + Object.defineProperty(this, 'infiniteThick', { + get() { + return this._infiniteThick }, - SSRShader.defines, - ), - uniforms: UniformsUtils.clone(SSRShader.uniforms), - vertexShader: SSRShader.vertexShader, - fragmentShader: SSRShader.fragmentShader, - blending: NoBlending, - }) - if (!isPerspectiveCamera) { - this.ssrMaterial.defines.isPerspectiveCamera = isPerspectiveCamera + set(val) { + if (this._infiniteThick === val) return + this._infiniteThick = val + this.ssrMaterial.defines.INFINITE_THICK = val + this.ssrMaterial.needsUpdate = true + }, + }) + + // beauty render target with depth buffer + + const depthTexture = new DepthTexture() + depthTexture.type = UnsignedShortType + depthTexture.minFilter = NearestFilter + depthTexture.magFilter = NearestFilter + + this.beautyRenderTarget = new WebGLRenderTarget(this.width, this.height, { + minFilter: NearestFilter, + magFilter: NearestFilter, + type: HalfFloatType, + depthTexture: depthTexture, + depthBuffer: true, + }) + + //for bouncing + this.prevRenderTarget = new WebGLRenderTarget(this.width, this.height, { + minFilter: NearestFilter, + magFilter: NearestFilter, + }) + + // normal render target + + this.normalRenderTarget = new WebGLRenderTarget(this.width, this.height, { + minFilter: NearestFilter, + magFilter: NearestFilter, + type: HalfFloatType, + }) + + // metalness render target + + this.metalnessRenderTarget = new WebGLRenderTarget(this.width, this.height, { + minFilter: NearestFilter, + magFilter: NearestFilter, + type: HalfFloatType, + }) + + // ssr render target + + this.ssrRenderTarget = new WebGLRenderTarget(this.width, this.height, { + minFilter: NearestFilter, + magFilter: NearestFilter, + }) + + this.blurRenderTarget = this.ssrRenderTarget.clone() + this.blurRenderTarget2 = this.ssrRenderTarget.clone() + // this.blurRenderTarget3 = this.ssrRenderTarget.clone(); + + // ssr material + + this.ssrMaterial = new ShaderMaterial({ + defines: Object.assign({}, SSRShader.defines, { + MAX_STEP: Math.sqrt(this.width * this.width + this.height * this.height), + }), + uniforms: UniformsUtils.clone(SSRShader.uniforms), + vertexShader: SSRShader.vertexShader, + fragmentShader: SSRShader.fragmentShader, + blending: NoBlending, + }) + + this.ssrMaterial.uniforms['tDiffuse'].value = this.beautyRenderTarget.texture + this.ssrMaterial.uniforms['tNormal'].value = this.normalRenderTarget.texture + this.ssrMaterial.defines.SELECTIVE = this.selective this.ssrMaterial.needsUpdate = true - } + this.ssrMaterial.uniforms['tMetalness'].value = this.metalnessRenderTarget.texture + this.ssrMaterial.uniforms['tDepth'].value = this.beautyRenderTarget.depthTexture + this.ssrMaterial.uniforms['cameraNear'].value = this.camera.near + this.ssrMaterial.uniforms['cameraFar'].value = this.camera.far + this.ssrMaterial.uniforms['thickness'].value = this.thickness + this.ssrMaterial.uniforms['resolution'].value.set(this.width, this.height) + this.ssrMaterial.uniforms['cameraProjectionMatrix'].value.copy(this.camera.projectionMatrix) + this.ssrMaterial.uniforms['cameraInverseProjectionMatrix'].value.copy(this.camera.projectionMatrixInverse) - this.ssrMaterial.uniforms['tDiffuse'].value = this.beautyRenderTarget.texture - this.ssrMaterial.uniforms['tNormal'].value = this.normalRenderTarget.texture - // if (this.isSelective) { - this.ssrMaterial.defines.isSelective = this.isSelective - this.ssrMaterial.needsUpdate = true - this.ssrMaterial.uniforms['tMetalness'].value = this.metalnessRenderTarget.texture - // } - this.ssrMaterial.uniforms['tDepth'].value = this.beautyRenderTarget.depthTexture - this.ssrMaterial.uniforms['cameraNear'].value = this.camera.near - this.ssrMaterial.uniforms['cameraFar'].value = this.camera.far - this.ssrMaterial.uniforms['surfDist'].value = this.surfDist - this.ssrMaterial.uniforms['resolution'].value.set(this.width, this.height) - this.ssrMaterial.uniforms['cameraProjectionMatrix'].value.copy(this.camera.projectionMatrix) - this.ssrMaterial.uniforms['cameraInverseProjectionMatrix'].value.copy(this.camera.projectionMatrixInverse) - - // normal material - - this.normalMaterial = new MeshNormalMaterial({ morphTargets }) - this.normalMaterial.blending = NoBlending - - // if (this.isSelective) { - // metalnessOn material - - this.metalnessOnMaterial = new MeshBasicMaterial({ - color: 'white', - }) - - // metalnessOff material - - this.metalnessOffMaterial = new MeshBasicMaterial({ - color: 'black', - }) - // } - - // blur material - - this.blurMaterial = new ShaderMaterial({ - defines: Object.assign({}, SSRBlurShader.defines), - uniforms: UniformsUtils.clone(SSRBlurShader.uniforms), - vertexShader: SSRBlurShader.vertexShader, - fragmentShader: SSRBlurShader.fragmentShader, - }) - this.blurMaterial.uniforms['tDiffuse'].value = this.ssrRenderTarget.texture - this.blurMaterial.uniforms['resolution'].value.set(this.width, this.height) - - // blur material 2 - - this.blurMaterial2 = new ShaderMaterial({ - defines: Object.assign({}, SSRBlurShader.defines), - uniforms: UniformsUtils.clone(SSRBlurShader.uniforms), - vertexShader: SSRBlurShader.vertexShader, - fragmentShader: SSRBlurShader.fragmentShader, - }) - this.blurMaterial2.uniforms['tDiffuse'].value = this.blurRenderTarget.texture - this.blurMaterial2.uniforms['resolution'].value.set(this.width, this.height) - - // // blur material 3 - - // this.blurMaterial3 = new ShaderMaterial({ - // defines: Object.assign({}, SSRBlurShader.defines), - // uniforms: UniformsUtils.clone(SSRBlurShader.uniforms), - // vertexShader: SSRBlurShader.vertexShader, - // fragmentShader: SSRBlurShader.fragmentShader - // }); - // this.blurMaterial3.uniforms['tDiffuse'].value = this.blurRenderTarget2.texture; - // this.blurMaterial3.uniforms['resolution'].value.set(this.width, this.height); - - // material for rendering the depth - - this.depthRenderMaterial = new ShaderMaterial({ - defines: Object.assign({}, SSRDepthShader.defines), - uniforms: UniformsUtils.clone(SSRDepthShader.uniforms), - vertexShader: SSRDepthShader.vertexShader, - fragmentShader: SSRDepthShader.fragmentShader, - blending: NoBlending, - }) - this.depthRenderMaterial.uniforms['tDepth'].value = this.beautyRenderTarget.depthTexture - this.depthRenderMaterial.uniforms['cameraNear'].value = this.camera.near - this.depthRenderMaterial.uniforms['cameraFar'].value = this.camera.far - - // material for rendering the content of a render target - - this.copyMaterial = new ShaderMaterial({ - uniforms: UniformsUtils.clone(CopyShader.uniforms), - vertexShader: CopyShader.vertexShader, - fragmentShader: CopyShader.fragmentShader, - transparent: true, - depthTest: false, - depthWrite: false, - blendSrc: SrcAlphaFactor, - blendDst: OneMinusSrcAlphaFactor, - blendEquation: AddEquation, - blendSrcAlpha: SrcAlphaFactor, - blendDstAlpha: OneMinusSrcAlphaFactor, - blendEquationAlpha: AddEquation, - // premultipliedAlpha:true, - }) - - this.fsQuad = new FullScreenQuad(null) - - this.originalClearColor = new Color() -} + // normal material + + this.normalMaterial = new MeshNormalMaterial() + this.normalMaterial.blending = NoBlending -SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { - constructor: SSRPass, + // metalnessOn material + + this.metalnessOnMaterial = new MeshBasicMaterial({ + color: 'white', + }) + + // metalnessOff material + + this.metalnessOffMaterial = new MeshBasicMaterial({ + color: 'black', + }) - dispose: function () { + // blur material + + this.blurMaterial = new ShaderMaterial({ + defines: Object.assign({}, SSRBlurShader.defines), + uniforms: UniformsUtils.clone(SSRBlurShader.uniforms), + vertexShader: SSRBlurShader.vertexShader, + fragmentShader: SSRBlurShader.fragmentShader, + }) + this.blurMaterial.uniforms['tDiffuse'].value = this.ssrRenderTarget.texture + this.blurMaterial.uniforms['resolution'].value.set(this.width, this.height) + + // blur material 2 + + this.blurMaterial2 = new ShaderMaterial({ + defines: Object.assign({}, SSRBlurShader.defines), + uniforms: UniformsUtils.clone(SSRBlurShader.uniforms), + vertexShader: SSRBlurShader.vertexShader, + fragmentShader: SSRBlurShader.fragmentShader, + }) + this.blurMaterial2.uniforms['tDiffuse'].value = this.blurRenderTarget.texture + this.blurMaterial2.uniforms['resolution'].value.set(this.width, this.height) + + // // blur material 3 + + // this.blurMaterial3 = new ShaderMaterial({ + // defines: Object.assign({}, SSRBlurShader.defines), + // uniforms: UniformsUtils.clone(SSRBlurShader.uniforms), + // vertexShader: SSRBlurShader.vertexShader, + // fragmentShader: SSRBlurShader.fragmentShader + // }); + // this.blurMaterial3.uniforms['tDiffuse'].value = this.blurRenderTarget2.texture; + // this.blurMaterial3.uniforms['resolution'].value.set(this.width, this.height); + + // material for rendering the depth + + this.depthRenderMaterial = new ShaderMaterial({ + defines: Object.assign({}, SSRDepthShader.defines), + uniforms: UniformsUtils.clone(SSRDepthShader.uniforms), + vertexShader: SSRDepthShader.vertexShader, + fragmentShader: SSRDepthShader.fragmentShader, + blending: NoBlending, + }) + this.depthRenderMaterial.uniforms['tDepth'].value = this.beautyRenderTarget.depthTexture + this.depthRenderMaterial.uniforms['cameraNear'].value = this.camera.near + this.depthRenderMaterial.uniforms['cameraFar'].value = this.camera.far + + // material for rendering the content of a render target + + this.copyMaterial = new ShaderMaterial({ + uniforms: UniformsUtils.clone(CopyShader.uniforms), + vertexShader: CopyShader.vertexShader, + fragmentShader: CopyShader.fragmentShader, + transparent: true, + depthTest: false, + depthWrite: false, + blendSrc: SrcAlphaFactor, + blendDst: OneMinusSrcAlphaFactor, + blendEquation: AddEquation, + blendSrcAlpha: SrcAlphaFactor, + blendDstAlpha: OneMinusSrcAlphaFactor, + blendEquationAlpha: AddEquation, + // premultipliedAlpha:true, + }) + + this.fsQuad = new FullScreenQuad(null) + + this.originalClearColor = new Color() + } + + dispose() { // dispose render targets this.beautyRenderTarget.dispose() this.prevRenderTarget.dispose() this.normalRenderTarget.dispose() - // if (this.isSelective) this.metalnessRenderTarget.dispose() this.ssrRenderTarget.dispose() this.blurRenderTarget.dispose() @@ -331,10 +303,8 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { // dispose materials this.normalMaterial.dispose() - // if (this.isSelective) { this.metalnessOnMaterial.dispose() this.metalnessOffMaterial.dispose() - // } this.blurMaterial.dispose() this.blurMaterial2.dispose() this.copyMaterial.dispose() @@ -343,24 +313,19 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { // dipsose full screen quad this.fsQuad.dispose() - }, + } - render: function (renderer, writeBuffer /*, readBuffer, deltaTime, maskActive */) { + render(renderer, writeBuffer /*, readBuffer, deltaTime, maskActive */) { // render beauty and depth - if (this.encoding) { - if ('colorSpace' in this.beautyRenderTarget.texture) { - this.beautyRenderTarget.texture.colorSpace = this.encoding === 3001 ? 'srgb' : 'srgb-linear' - } else { - this.beautyRenderTarget.texture.encoding = this.encoding - } - } renderer.setRenderTarget(this.beautyRenderTarget) renderer.clear() if (this.groundReflector) { + this.groundReflector.visible = false this.groundReflector.doRender(this.renderer, this.scene, this.camera) this.groundReflector.visible = true } + renderer.render(this.scene, this.camera) if (this.groundReflector) this.groundReflector.visible = false @@ -370,7 +335,7 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { // render metalnesses - if (this.isSelective) { + if (this.selective) { this.renderMetalness(renderer, this.metalnessOnMaterial, this.metalnessRenderTarget, 0, 0) } @@ -378,13 +343,12 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { this.ssrMaterial.uniforms['opacity'].value = this.opacity this.ssrMaterial.uniforms['maxDistance'].value = this.maxDistance - this.ssrMaterial.uniforms['surfDist'].value = this.surfDist - this.ssrMaterial.uniforms['thickTolerance'].value = this.thickTolerance + this.ssrMaterial.uniforms['thickness'].value = this.thickness this.renderPass(renderer, this.ssrMaterial, this.ssrRenderTarget) // render blur - if (this.isBlur) { + if (this.blur) { this.renderPass(renderer, this.blurMaterial, this.blurRenderTarget) this.renderPass(renderer, this.blurMaterial2, this.blurRenderTarget2) // this.renderPass(renderer, this.blurMaterial3, this.blurRenderTarget3); @@ -394,12 +358,12 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { switch (this.output) { case SSRPass.OUTPUT.Default: - if (this.isBouncing) { + if (this.bouncing) { this.copyMaterial.uniforms['tDiffuse'].value = this.beautyRenderTarget.texture this.copyMaterial.blending = NoBlending this.renderPass(renderer, this.copyMaterial, this.prevRenderTarget) - if (this.isBlur) this.copyMaterial.uniforms['tDiffuse'].value = this.blurRenderTarget2.texture + if (this.blur) this.copyMaterial.uniforms['tDiffuse'].value = this.blurRenderTarget2.texture else this.copyMaterial.uniforms['tDiffuse'].value = this.ssrRenderTarget.texture this.copyMaterial.blending = NormalBlending this.renderPass(renderer, this.copyMaterial, this.prevRenderTarget) @@ -412,7 +376,7 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { this.copyMaterial.blending = NoBlending this.renderPass(renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer) - if (this.isBlur) this.copyMaterial.uniforms['tDiffuse'].value = this.blurRenderTarget2.texture + if (this.blur) this.copyMaterial.uniforms['tDiffuse'].value = this.blurRenderTarget2.texture else this.copyMaterial.uniforms['tDiffuse'].value = this.ssrRenderTarget.texture this.copyMaterial.blending = NormalBlending this.renderPass(renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer) @@ -420,13 +384,13 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { break case SSRPass.OUTPUT.SSR: - if (this.isBlur) this.copyMaterial.uniforms['tDiffuse'].value = this.blurRenderTarget2.texture + if (this.blur) this.copyMaterial.uniforms['tDiffuse'].value = this.blurRenderTarget2.texture else this.copyMaterial.uniforms['tDiffuse'].value = this.ssrRenderTarget.texture this.copyMaterial.blending = NoBlending this.renderPass(renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer) - if (this.isBouncing) { - if (this.isBlur) this.copyMaterial.uniforms['tDiffuse'].value = this.blurRenderTarget2.texture + if (this.bouncing) { + if (this.blur) this.copyMaterial.uniforms['tDiffuse'].value = this.blurRenderTarget2.texture else this.copyMaterial.uniforms['tDiffuse'].value = this.beautyRenderTarget.texture this.copyMaterial.blending = NoBlending this.renderPass(renderer, this.copyMaterial, this.prevRenderTarget) @@ -467,13 +431,13 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { default: console.warn('THREE.SSRPass: Unknown output type.') } - }, + } - renderPass: function (renderer, passMaterial, renderTarget, clearColor, clearAlpha) { + renderPass(renderer, passMaterial, renderTarget, clearColor, clearAlpha) { // save original state this.originalClearColor.copy(renderer.getClearColor(this.tempColor)) - var originalClearAlpha = renderer.getClearAlpha(this.tempColor) - var originalAutoClear = renderer.autoClear + const originalClearAlpha = renderer.getClearAlpha(this.tempColor) + const originalAutoClear = renderer.autoClear renderer.setRenderTarget(renderTarget) @@ -492,12 +456,12 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { renderer.autoClear = originalAutoClear renderer.setClearColor(this.originalClearColor) renderer.setClearAlpha(originalClearAlpha) - }, + } - renderOverride: function (renderer, overrideMaterial, renderTarget, clearColor, clearAlpha) { + renderOverride(renderer, overrideMaterial, renderTarget, clearColor, clearAlpha) { this.originalClearColor.copy(renderer.getClearColor(this.tempColor)) - var originalClearAlpha = renderer.getClearAlpha(this.tempColor) - var originalAutoClear = renderer.autoClear + const originalClearAlpha = renderer.getClearAlpha(this.tempColor) + const originalAutoClear = renderer.autoClear renderer.setRenderTarget(renderTarget) renderer.autoClear = false @@ -520,12 +484,12 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { renderer.autoClear = originalAutoClear renderer.setClearColor(this.originalClearColor) renderer.setClearAlpha(originalClearAlpha) - }, + } - renderMetalness: function (renderer, overrideMaterial, renderTarget, clearColor, clearAlpha) { + renderMetalness(renderer, overrideMaterial, renderTarget, clearColor, clearAlpha) { this.originalClearColor.copy(renderer.getClearColor(this.tempColor)) - var originalClearAlpha = renderer.getClearAlpha(this.tempColor) - var originalAutoClear = renderer.autoClear + const originalClearAlpha = renderer.getClearAlpha(this.tempColor) + const originalAutoClear = renderer.autoClear renderer.setRenderTarget(renderTarget) renderer.autoClear = false @@ -540,7 +504,7 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { } this.scene.traverseVisible((child) => { - child._SSRPassMaterialBack = child.material + child._SSRPassBackupMaterial = child.material if (this._selects.includes(child)) { child.material = this.metalnessOnMaterial } else { @@ -549,7 +513,7 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { }) renderer.render(this.scene, this.camera) this.scene.traverseVisible((child) => { - child.material = child._SSRPassMaterialBack + child.material = child._SSRPassBackupMaterial }) // restore original state @@ -557,9 +521,9 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { renderer.autoClear = originalAutoClear renderer.setClearColor(this.originalClearColor) renderer.setClearAlpha(originalClearAlpha) - }, + } - setSize: function (width, height) { + setSize(width, height) { this.width = width this.height = height @@ -569,7 +533,6 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { this.prevRenderTarget.setSize(width, height) this.ssrRenderTarget.setSize(width, height) this.normalRenderTarget.setSize(width, height) - // if (this.isSelective) this.metalnessRenderTarget.setSize(width, height) this.blurRenderTarget.setSize(width, height) this.blurRenderTarget2.setSize(width, height) @@ -581,16 +544,7 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { this.blurMaterial.uniforms['resolution'].value.set(width, height) this.blurMaterial2.uniforms['resolution'].value.set(width, height) - }, -}) - -SSRPass.OUTPUT = { - Default: 0, - SSR: 1, - Beauty: 3, - Depth: 4, - Normal: 5, - Metalness: 7, + } } export { SSRPass } diff --git a/src/postprocessing/TAARenderPass.js b/src/postprocessing/TAARenderPass.js index 6183bde9..4450f4c7 100644 --- a/src/postprocessing/TAARenderPass.js +++ b/src/postprocessing/TAARenderPass.js @@ -1,5 +1,5 @@ -import { WebGLRenderTarget } from 'three' -import { SSAARenderPass } from '../postprocessing/SSAARenderPass' +import { HalfFloatType, WebGLRenderTarget } from 'three' +import { SSAARenderPass } from './SSAARenderPass' /** * @@ -13,62 +13,54 @@ import { SSAARenderPass } from '../postprocessing/SSAARenderPass' * */ -var TAARenderPass = function (scene, camera, clearColor, clearAlpha) { - if (SSAARenderPass === undefined) { - console.error('THREE.TAARenderPass relies on SSAARenderPass') - } - - SSAARenderPass.call(this, scene, camera, clearColor, clearAlpha) - - this.sampleLevel = 0 - this.accumulate = false -} - -TAARenderPass.JitterVectors = SSAARenderPass.JitterVectors +class TAARenderPass extends SSAARenderPass { + constructor(scene, camera, clearColor, clearAlpha) { + super(scene, camera, clearColor, clearAlpha) -TAARenderPass.prototype = Object.assign(Object.create(SSAARenderPass.prototype), { - constructor: TAARenderPass, + this.sampleLevel = 0 + this.accumulate = false + } - render: function (renderer, writeBuffer, readBuffer, deltaTime) { - if (!this.accumulate) { - SSAARenderPass.prototype.render.call(this, renderer, writeBuffer, readBuffer, deltaTime) + render(renderer, writeBuffer, readBuffer, deltaTime) { + if (this.accumulate === false) { + super.render(renderer, writeBuffer, readBuffer, deltaTime) this.accumulateIndex = -1 return } - var jitterOffsets = TAARenderPass.JitterVectors[5] + const jitterOffsets = _JitterVectors[5] - if (!this.sampleRenderTarget) { - this.sampleRenderTarget = new WebGLRenderTarget(readBuffer.width, readBuffer.height, this.params) + if (this.sampleRenderTarget === undefined) { + this.sampleRenderTarget = new WebGLRenderTarget(readBuffer.width, readBuffer.height, { type: HalfFloatType }) this.sampleRenderTarget.texture.name = 'TAARenderPass.sample' } - if (!this.holdRenderTarget) { - this.holdRenderTarget = new WebGLRenderTarget(readBuffer.width, readBuffer.height, this.params) + if (this.holdRenderTarget === undefined) { + this.holdRenderTarget = new WebGLRenderTarget(readBuffer.width, readBuffer.height, { type: HalfFloatType }) this.holdRenderTarget.texture.name = 'TAARenderPass.hold' } - if (this.accumulate && this.accumulateIndex === -1) { - SSAARenderPass.prototype.render.call(this, renderer, this.holdRenderTarget, readBuffer, deltaTime) + if (this.accumulateIndex === -1) { + super.render(renderer, this.holdRenderTarget, readBuffer, deltaTime) this.accumulateIndex = 0 } - var autoClear = renderer.autoClear + const autoClear = renderer.autoClear renderer.autoClear = false - var sampleWeight = 1.0 / jitterOffsets.length + const sampleWeight = 1.0 / jitterOffsets.length if (this.accumulateIndex >= 0 && this.accumulateIndex < jitterOffsets.length) { this.copyUniforms['opacity'].value = sampleWeight this.copyUniforms['tDiffuse'].value = writeBuffer.texture // render the scene multiple times, each slightly jitter offset from the last and accumulate the results. - var numSamplesPerFrame = Math.pow(2, this.sampleLevel) + const numSamplesPerFrame = Math.pow(2, this.sampleLevel) for (let i = 0; i < numSamplesPerFrame; i++) { - var j = this.accumulateIndex - var jitterOffset = jitterOffsets[j] + const j = this.accumulateIndex + const jitterOffset = jitterOffsets[j] if (this.camera.setViewOffset) { this.camera.setViewOffset( @@ -97,7 +89,7 @@ TAARenderPass.prototype = Object.assign(Object.create(SSAARenderPass.prototype), if (this.camera.clearViewOffset) this.camera.clearViewOffset() } - var accumulationWeight = this.accumulateIndex * sampleWeight + const accumulationWeight = this.accumulateIndex * sampleWeight if (accumulationWeight > 0) { this.copyUniforms['opacity'].value = 1.0 @@ -116,7 +108,47 @@ TAARenderPass.prototype = Object.assign(Object.create(SSAARenderPass.prototype), } renderer.autoClear = autoClear - }, -}) + } + + dispose() { + super.dispose() + + if (this.sampleRenderTarget !== undefined) this.sampleRenderTarget.dispose() + if (this.holdRenderTarget !== undefined) this.holdRenderTarget.dispose() + } +} + +// prettier-ignore +const _JitterVectors = [ + [ + [ 0, 0 ] + ], + [ + [ 4, 4 ], [ - 4, - 4 ] + ], + [ + [ - 2, - 6 ], [ 6, - 2 ], [ - 6, 2 ], [ 2, 6 ] + ], + [ + [ 1, - 3 ], [ - 1, 3 ], [ 5, 1 ], [ - 3, - 5 ], + [ - 5, 5 ], [ - 7, - 1 ], [ 3, 7 ], [ 7, - 7 ] + ], + [ + [ 1, 1 ], [ - 1, - 3 ], [ - 3, 2 ], [ 4, - 1 ], + [ - 5, - 2 ], [ 2, 5 ], [ 5, 3 ], [ 3, - 5 ], + [ - 2, 6 ], [ 0, - 7 ], [ - 4, - 6 ], [ - 6, 4 ], + [ - 8, 0 ], [ 7, - 4 ], [ 6, 7 ], [ - 7, - 8 ] + ], + [ + [ - 4, - 7 ], [ - 7, - 5 ], [ - 3, - 5 ], [ - 5, - 4 ], + [ - 1, - 4 ], [ - 2, - 2 ], [ - 6, - 1 ], [ - 4, 0 ], + [ - 7, 1 ], [ - 1, 2 ], [ - 6, 3 ], [ - 3, 3 ], + [ - 7, 6 ], [ - 3, 6 ], [ - 5, 7 ], [ - 1, 7 ], + [ 5, - 7 ], [ 1, - 6 ], [ 6, - 5 ], [ 4, - 4 ], + [ 2, - 3 ], [ 7, - 2 ], [ 1, - 1 ], [ 4, - 1 ], + [ 2, 1 ], [ 6, 2 ], [ 0, 4 ], [ 4, 4 ], + [ 2, 5 ], [ 7, 5 ], [ 5, 6 ], [ 3, 7 ] + ] +]; export { TAARenderPass } diff --git a/src/postprocessing/TexturePass.d.ts b/src/postprocessing/TexturePass.d.ts index accd7bd3..188185fa 100644 --- a/src/postprocessing/TexturePass.d.ts +++ b/src/postprocessing/TexturePass.d.ts @@ -1,6 +1,6 @@ import { Texture, ShaderMaterial } from 'three' -import { Pass } from './Pass' +import { Pass, FullScreenQuad } from './Pass' export class TexturePass extends Pass { constructor(map: Texture, opacity?: number) @@ -8,5 +8,5 @@ export class TexturePass extends Pass { opacity: number uniforms: object material: ShaderMaterial - fsQuad: object + fsQuad: FullScreenQuad } diff --git a/src/postprocessing/TexturePass.js b/src/postprocessing/TexturePass.js index 8b7c845f..5c1a4ecb 100644 --- a/src/postprocessing/TexturePass.js +++ b/src/postprocessing/TexturePass.js @@ -1,35 +1,33 @@ import { ShaderMaterial, UniformsUtils } from 'three' -import { Pass, FullScreenQuad } from '../postprocessing/Pass' +import { Pass, FullScreenQuad } from './Pass' import { CopyShader } from '../shaders/CopyShader' -var TexturePass = function (map, opacity) { - if (CopyShader === undefined) console.error('THREE.TexturePass relies on CopyShader') +class TexturePass extends Pass { + constructor(map, opacity) { + super() - var shader = CopyShader + const shader = CopyShader - this.map = map - this.opacity = opacity !== undefined ? opacity : 1.0 + this.map = map + this.opacity = opacity !== undefined ? opacity : 1.0 - this.uniforms = UniformsUtils.clone(shader.uniforms) + this.uniforms = UniformsUtils.clone(shader.uniforms) - this.material = new ShaderMaterial({ - uniforms: this.uniforms, - vertexShader: shader.vertexShader, - fragmentShader: shader.fragmentShader, - depthTest: false, - depthWrite: false, - }) + this.material = new ShaderMaterial({ + uniforms: this.uniforms, + vertexShader: shader.vertexShader, + fragmentShader: shader.fragmentShader, + depthTest: false, + depthWrite: false, + }) - this.needsSwap = false + this.needsSwap = false - this.fsQuad = new FullScreenQuad(null) -} - -TexturePass.prototype = Object.assign(Object.create(Pass.prototype), { - constructor: TexturePass, + this.fsQuad = new FullScreenQuad(null) + } - render: function (renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */) { - var oldAutoClear = renderer.autoClear + render(renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */) { + const oldAutoClear = renderer.autoClear renderer.autoClear = false this.fsQuad.material = this.material @@ -43,7 +41,13 @@ TexturePass.prototype = Object.assign(Object.create(Pass.prototype), { this.fsQuad.render(renderer) renderer.autoClear = oldAutoClear - }, -}) + } + + dispose() { + this.material.dispose() + + this.fsQuad.dispose() + } +} export { TexturePass } diff --git a/src/postprocessing/UnrealBloomPass.js b/src/postprocessing/UnrealBloomPass.js index 26504d91..1ff2b789 100644 --- a/src/postprocessing/UnrealBloomPass.js +++ b/src/postprocessing/UnrealBloomPass.js @@ -1,16 +1,15 @@ import { AdditiveBlending, Color, - LinearFilter, + HalfFloatType, MeshBasicMaterial, - RGBAFormat, ShaderMaterial, UniformsUtils, Vector2, Vector3, WebGLRenderTarget, } from 'three' -import { Pass, FullScreenQuad } from '../postprocessing/Pass' +import { Pass, FullScreenQuad } from './Pass' import { CopyShader } from '../shaders/CopyShader' import { LuminosityHighPassShader } from '../shaders/LuminosityHighPassShader' @@ -23,141 +22,134 @@ import { LuminosityHighPassShader } from '../shaders/LuminosityHighPassShader' * Reference: * - https://docs.unrealengine.com/latest/INT/Engine/Rendering/PostProcessEffects/Bloom/ */ -var UnrealBloomPass = function (resolution, strength, radius, threshold) { - this.strength = strength !== undefined ? strength : 1 - this.radius = radius - this.threshold = threshold - this.resolution = resolution !== undefined ? new Vector2(resolution.x, resolution.y) : new Vector2(256, 256) - - // create color only once here, reuse it later inside the render function - this.clearColor = new Color(0, 0, 0) - - // render targets - var pars = { - minFilter: LinearFilter, - magFilter: LinearFilter, - format: RGBAFormat, - } - this.renderTargetsHorizontal = [] - this.renderTargetsVertical = [] - this.nMips = 5 - var resx = Math.round(this.resolution.x / 2) - var resy = Math.round(this.resolution.y / 2) +class UnrealBloomPass extends Pass { + static BlurDirectionX = /* @__PURE__ */ new Vector2(1.0, 0.0) + static BlurDirectionY = /* @__PURE__ */ new Vector2(0.0, 1.0) - this.renderTargetBright = new WebGLRenderTarget(resx, resy, pars) - this.renderTargetBright.texture.name = 'UnrealBloomPass.bright' - this.renderTargetBright.texture.generateMipmaps = false + constructor(resolution, strength, radius, threshold) { + super() - for (let i = 0; i < this.nMips; i++) { - var renderTargetHorizonal = new WebGLRenderTarget(resx, resy, pars) + this.strength = strength !== undefined ? strength : 1 + this.radius = radius + this.threshold = threshold + this.resolution = resolution !== undefined ? new Vector2(resolution.x, resolution.y) : new Vector2(256, 256) - renderTargetHorizonal.texture.name = 'UnrealBloomPass.h' + i - renderTargetHorizonal.texture.generateMipmaps = false + // create color only once here, reuse it later inside the render function + this.clearColor = new Color(0, 0, 0) - this.renderTargetsHorizontal.push(renderTargetHorizonal) + // render targets + this.renderTargetsHorizontal = [] + this.renderTargetsVertical = [] + this.nMips = 5 + let resx = Math.round(this.resolution.x / 2) + let resy = Math.round(this.resolution.y / 2) - var renderTargetVertical = new WebGLRenderTarget(resx, resy, pars) + this.renderTargetBright = new WebGLRenderTarget(resx, resy, { type: HalfFloatType }) + this.renderTargetBright.texture.name = 'UnrealBloomPass.bright' + this.renderTargetBright.texture.generateMipmaps = false - renderTargetVertical.texture.name = 'UnrealBloomPass.v' + i - renderTargetVertical.texture.generateMipmaps = false + for (let i = 0; i < this.nMips; i++) { + const renderTargetHorizonal = new WebGLRenderTarget(resx, resy, { type: HalfFloatType }) - this.renderTargetsVertical.push(renderTargetVertical) + renderTargetHorizonal.texture.name = 'UnrealBloomPass.h' + i + renderTargetHorizonal.texture.generateMipmaps = false - resx = Math.round(resx / 2) + this.renderTargetsHorizontal.push(renderTargetHorizonal) - resy = Math.round(resy / 2) - } + const renderTargetVertical = new WebGLRenderTarget(resx, resy, { type: HalfFloatType }) - // luminosity high pass material + renderTargetVertical.texture.name = 'UnrealBloomPass.v' + i + renderTargetVertical.texture.generateMipmaps = false - if (LuminosityHighPassShader === undefined) console.error('THREE.UnrealBloomPass relies on LuminosityHighPassShader') + this.renderTargetsVertical.push(renderTargetVertical) - var highPassShader = LuminosityHighPassShader - this.highPassUniforms = UniformsUtils.clone(highPassShader.uniforms) + resx = Math.round(resx / 2) - this.highPassUniforms['luminosityThreshold'].value = threshold - this.highPassUniforms['smoothWidth'].value = 0.01 + resy = Math.round(resy / 2) + } - this.materialHighPassFilter = new ShaderMaterial({ - uniforms: this.highPassUniforms, - vertexShader: highPassShader.vertexShader, - fragmentShader: highPassShader.fragmentShader, - defines: {}, - }) + // luminosity high pass material - // Gaussian Blur Materials - this.separableBlurMaterials = [] - var kernelSizeArray = [3, 5, 7, 9, 11] - var resx = Math.round(this.resolution.x / 2) - var resy = Math.round(this.resolution.y / 2) + const highPassShader = LuminosityHighPassShader + this.highPassUniforms = UniformsUtils.clone(highPassShader.uniforms) - for (let i = 0; i < this.nMips; i++) { - this.separableBlurMaterials.push(this.getSeperableBlurMaterial(kernelSizeArray[i])) + this.highPassUniforms['luminosityThreshold'].value = threshold + this.highPassUniforms['smoothWidth'].value = 0.01 - this.separableBlurMaterials[i].uniforms['texSize'].value = new Vector2(resx, resy) + this.materialHighPassFilter = new ShaderMaterial({ + uniforms: this.highPassUniforms, + vertexShader: highPassShader.vertexShader, + fragmentShader: highPassShader.fragmentShader, + defines: {}, + }) - resx = Math.round(resx / 2) + // Gaussian Blur Materials + this.separableBlurMaterials = [] + const kernelSizeArray = [3, 5, 7, 9, 11] + resx = Math.round(this.resolution.x / 2) + resy = Math.round(this.resolution.y / 2) - resy = Math.round(resy / 2) - } + for (let i = 0; i < this.nMips; i++) { + this.separableBlurMaterials.push(this.getSeperableBlurMaterial(kernelSizeArray[i])) - // Composite material - this.compositeMaterial = this.getCompositeMaterial(this.nMips) - this.compositeMaterial.uniforms['blurTexture1'].value = this.renderTargetsVertical[0].texture - this.compositeMaterial.uniforms['blurTexture2'].value = this.renderTargetsVertical[1].texture - this.compositeMaterial.uniforms['blurTexture3'].value = this.renderTargetsVertical[2].texture - this.compositeMaterial.uniforms['blurTexture4'].value = this.renderTargetsVertical[3].texture - this.compositeMaterial.uniforms['blurTexture5'].value = this.renderTargetsVertical[4].texture - this.compositeMaterial.uniforms['bloomStrength'].value = strength - this.compositeMaterial.uniforms['bloomRadius'].value = 0.1 - this.compositeMaterial.needsUpdate = true - - var bloomFactors = [1.0, 0.8, 0.6, 0.4, 0.2] - this.compositeMaterial.uniforms['bloomFactors'].value = bloomFactors - this.bloomTintColors = [ - new Vector3(1, 1, 1), - new Vector3(1, 1, 1), - new Vector3(1, 1, 1), - new Vector3(1, 1, 1), - new Vector3(1, 1, 1), - ] - this.compositeMaterial.uniforms['bloomTintColors'].value = this.bloomTintColors - - // copy material - if (CopyShader === undefined) { - console.error('THREE.UnrealBloomPass relies on CopyShader') - } + this.separableBlurMaterials[i].uniforms['texSize'].value = new Vector2(resx, resy) - var copyShader = CopyShader + resx = Math.round(resx / 2) - this.copyUniforms = UniformsUtils.clone(copyShader.uniforms) - this.copyUniforms['opacity'].value = 1.0 + resy = Math.round(resy / 2) + } - this.materialCopy = new ShaderMaterial({ - uniforms: this.copyUniforms, - vertexShader: copyShader.vertexShader, - fragmentShader: copyShader.fragmentShader, - blending: AdditiveBlending, - depthTest: false, - depthWrite: false, - transparent: true, - }) + // Composite material + this.compositeMaterial = this.getCompositeMaterial(this.nMips) + this.compositeMaterial.uniforms['blurTexture1'].value = this.renderTargetsVertical[0].texture + this.compositeMaterial.uniforms['blurTexture2'].value = this.renderTargetsVertical[1].texture + this.compositeMaterial.uniforms['blurTexture3'].value = this.renderTargetsVertical[2].texture + this.compositeMaterial.uniforms['blurTexture4'].value = this.renderTargetsVertical[3].texture + this.compositeMaterial.uniforms['blurTexture5'].value = this.renderTargetsVertical[4].texture + this.compositeMaterial.uniforms['bloomStrength'].value = strength + this.compositeMaterial.uniforms['bloomRadius'].value = 0.1 + this.compositeMaterial.needsUpdate = true + + const bloomFactors = [1.0, 0.8, 0.6, 0.4, 0.2] + this.compositeMaterial.uniforms['bloomFactors'].value = bloomFactors + this.bloomTintColors = [ + new Vector3(1, 1, 1), + new Vector3(1, 1, 1), + new Vector3(1, 1, 1), + new Vector3(1, 1, 1), + new Vector3(1, 1, 1), + ] + this.compositeMaterial.uniforms['bloomTintColors'].value = this.bloomTintColors - this.enabled = true - this.needsSwap = false + // copy material - this._oldClearColor = new Color() - this.oldClearAlpha = 1 + const copyShader = CopyShader - this.basic = new MeshBasicMaterial() + this.copyUniforms = UniformsUtils.clone(copyShader.uniforms) + this.copyUniforms['opacity'].value = 1.0 - this.fsQuad = new FullScreenQuad(null) -} + this.materialCopy = new ShaderMaterial({ + uniforms: this.copyUniforms, + vertexShader: copyShader.vertexShader, + fragmentShader: copyShader.fragmentShader, + blending: AdditiveBlending, + depthTest: false, + depthWrite: false, + transparent: true, + }) -UnrealBloomPass.prototype = Object.assign(Object.create(Pass.prototype), { - constructor: UnrealBloomPass, + this.enabled = true + this.needsSwap = false - dispose: function () { + this._oldClearColor = new Color() + this.oldClearAlpha = 1 + + this.basic = new MeshBasicMaterial() + + this.fsQuad = new FullScreenQuad(null) + } + + dispose() { for (let i = 0; i < this.renderTargetsHorizontal.length; i++) { this.renderTargetsHorizontal[i].dispose() } @@ -167,11 +159,25 @@ UnrealBloomPass.prototype = Object.assign(Object.create(Pass.prototype), { } this.renderTargetBright.dispose() - }, - setSize: function (width, height) { - var resx = Math.round(width / 2) - var resy = Math.round(height / 2) + // + + for (let i = 0; i < this.separableBlurMaterials.length; i++) { + this.separableBlurMaterials[i].dispose() + } + + this.compositeMaterial.dispose() + this.materialCopy.dispose() + this.basic.dispose() + + // + + this.fsQuad.dispose() + } + + setSize(width, height) { + let resx = Math.round(width / 2) + let resy = Math.round(height / 2) this.renderTargetBright.setSize(resx, resy) @@ -184,12 +190,12 @@ UnrealBloomPass.prototype = Object.assign(Object.create(Pass.prototype), { resx = Math.round(resx / 2) resy = Math.round(resy / 2) } - }, + } - render: function (renderer, writeBuffer, readBuffer, deltaTime, maskActive) { + render(renderer, writeBuffer, readBuffer, deltaTime, maskActive) { renderer.getClearColor(this._oldClearColor) this.oldClearAlpha = renderer.getClearAlpha() - var oldAutoClear = renderer.autoClear + const oldAutoClear = renderer.autoClear renderer.autoClear = false renderer.setClearColor(this.clearColor, 0) @@ -219,7 +225,7 @@ UnrealBloomPass.prototype = Object.assign(Object.create(Pass.prototype), { // 2. Blur All the mips progressively - var inputRenderTarget = this.renderTargetBright + let inputRenderTarget = this.renderTargetBright for (let i = 0; i < this.nMips; i++) { this.fsQuad.material = this.separableBlurMaterials[i] @@ -269,9 +275,9 @@ UnrealBloomPass.prototype = Object.assign(Object.create(Pass.prototype), { renderer.setClearColor(this._oldClearColor, this.oldClearAlpha) renderer.autoClear = oldAutoClear - }, + } - getSeperableBlurMaterial: function (kernelRadius) { + getSeperableBlurMaterial(kernelRadius) { return new ShaderMaterial({ defines: { KERNEL_RADIUS: kernelRadius, @@ -284,42 +290,41 @@ UnrealBloomPass.prototype = Object.assign(Object.create(Pass.prototype), { direction: { value: new Vector2(0.5, 0.5) }, }, - vertexShader: - 'varying vec2 vUv;\n' + - 'void main() {\n' + - ' vUv = uv;\n' + - ' gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n' + - '}', - fragmentShader: - '#include ' + - 'varying vec2 vUv;\n' + - 'uniform sampler2D colorTexture;\n' + - 'uniform vec2 texSize;' + - 'uniform vec2 direction;' + - '\n' + - 'float gaussianPdf(in float x, in float sigma) {' + - ' return 0.39894 * exp( -0.5 * x * x/( sigma * sigma))/sigma;' + - '}' + - 'void main() {\n' + - ' vec2 invSize = 1.0 / texSize;' + - ' float fSigma = float(SIGMA);' + - ' float weightSum = gaussianPdf(0.0, fSigma);' + - ' vec3 diffuseSum = texture2D( colorTexture, vUv).rgb * weightSum;' + - ' for( int i = 1; i < KERNEL_RADIUS; i ++ ) {' + - ' float x = float(i);' + - ' float w = gaussianPdf(x, fSigma);' + - ' vec2 uvOffset = direction * invSize * x;' + - ' vec3 sample1 = texture2D( colorTexture, vUv + uvOffset).rgb;' + - ' vec3 sample2 = texture2D( colorTexture, vUv - uvOffset).rgb;' + - ' diffuseSum += (sample1 + sample2) * w;' + - ' weightSum += 2.0 * w;' + - ' }' + - ' gl_FragColor = vec4(diffuseSum/weightSum, 1.0);\n' + - '}', + vertexShader: `varying vec2 vUv; + void main() { + vUv = uv; + gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); + }`, + + fragmentShader: `#include + varying vec2 vUv; + uniform sampler2D colorTexture; + uniform vec2 texSize; + uniform vec2 direction; + + float gaussianPdf(in float x, in float sigma) { + return 0.39894 * exp( -0.5 * x * x/( sigma * sigma))/sigma; + } + void main() { + vec2 invSize = 1.0 / texSize; + float fSigma = float(SIGMA); + float weightSum = gaussianPdf(0.0, fSigma); + vec3 diffuseSum = texture2D( colorTexture, vUv).rgb * weightSum; + for( int i = 1; i < KERNEL_RADIUS; i ++ ) { + float x = float(i); + float w = gaussianPdf(x, fSigma); + vec2 uvOffset = direction * invSize * x; + vec3 sample1 = texture2D( colorTexture, vUv + uvOffset).rgb; + vec3 sample2 = texture2D( colorTexture, vUv - uvOffset).rgb; + diffuseSum += (sample1 + sample2) * w; + weightSum += 2.0 * w; + } + gl_FragColor = vec4(diffuseSum/weightSum, 1.0); + }`, }) - }, + } - getCompositeMaterial: function (nMips) { + getCompositeMaterial(nMips) { return new ShaderMaterial({ defines: { NUM_MIPS: nMips, @@ -331,49 +336,43 @@ UnrealBloomPass.prototype = Object.assign(Object.create(Pass.prototype), { blurTexture3: { value: null }, blurTexture4: { value: null }, blurTexture5: { value: null }, - dirtTexture: { value: null }, bloomStrength: { value: 1.0 }, bloomFactors: { value: null }, bloomTintColors: { value: null }, bloomRadius: { value: 0.0 }, }, - vertexShader: - 'varying vec2 vUv;\n' + - 'void main() {\n' + - ' vUv = uv;\n' + - ' gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n' + - '}', - fragmentShader: - 'varying vec2 vUv;' + - 'uniform sampler2D blurTexture1;' + - 'uniform sampler2D blurTexture2;' + - 'uniform sampler2D blurTexture3;' + - 'uniform sampler2D blurTexture4;' + - 'uniform sampler2D blurTexture5;' + - 'uniform sampler2D dirtTexture;' + - 'uniform float bloomStrength;' + - 'uniform float bloomRadius;' + - 'uniform float bloomFactors[NUM_MIPS];' + - 'uniform vec3 bloomTintColors[NUM_MIPS];' + - '' + - 'float lerpBloomFactor(const in float factor) { ' + - ' float mirrorFactor = 1.2 - factor;' + - ' return mix(factor, mirrorFactor, bloomRadius);' + - '}' + - '' + - 'void main() {' + - ' gl_FragColor = bloomStrength * ( lerpBloomFactor(bloomFactors[0]) * vec4(bloomTintColors[0], 1.0) * texture2D(blurTexture1, vUv) + ' + - ' lerpBloomFactor(bloomFactors[1]) * vec4(bloomTintColors[1], 1.0) * texture2D(blurTexture2, vUv) + ' + - ' lerpBloomFactor(bloomFactors[2]) * vec4(bloomTintColors[2], 1.0) * texture2D(blurTexture3, vUv) + ' + - ' lerpBloomFactor(bloomFactors[3]) * vec4(bloomTintColors[3], 1.0) * texture2D(blurTexture4, vUv) + ' + - ' lerpBloomFactor(bloomFactors[4]) * vec4(bloomTintColors[4], 1.0) * texture2D(blurTexture5, vUv) );' + - '}', + vertexShader: `varying vec2 vUv; + void main() { + vUv = uv; + gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); + }`, + + fragmentShader: `varying vec2 vUv; + uniform sampler2D blurTexture1; + uniform sampler2D blurTexture2; + uniform sampler2D blurTexture3; + uniform sampler2D blurTexture4; + uniform sampler2D blurTexture5; + uniform float bloomStrength; + uniform float bloomRadius; + uniform float bloomFactors[NUM_MIPS]; + uniform vec3 bloomTintColors[NUM_MIPS]; + + float lerpBloomFactor(const in float factor) { + float mirrorFactor = 1.2 - factor; + return mix(factor, mirrorFactor, bloomRadius); + } + + void main() { + gl_FragColor = bloomStrength * ( lerpBloomFactor(bloomFactors[0]) * vec4(bloomTintColors[0], 1.0) * texture2D(blurTexture1, vUv) + + lerpBloomFactor(bloomFactors[1]) * vec4(bloomTintColors[1], 1.0) * texture2D(blurTexture2, vUv) + + lerpBloomFactor(bloomFactors[2]) * vec4(bloomTintColors[2], 1.0) * texture2D(blurTexture3, vUv) + + lerpBloomFactor(bloomFactors[3]) * vec4(bloomTintColors[3], 1.0) * texture2D(blurTexture4, vUv) + + lerpBloomFactor(bloomFactors[4]) * vec4(bloomTintColors[4], 1.0) * texture2D(blurTexture5, vUv) ); + }`, }) - }, -}) - -UnrealBloomPass.BlurDirectionX = new Vector2(1.0, 0.0) -UnrealBloomPass.BlurDirectionY = new Vector2(0.0, 1.0) + } +} export { UnrealBloomPass }