elation-engine
Version:
WebGL/WebVR engine written in Javascript
1,790 lines (1,168 loc) • 48.3 kB
JavaScript
/**
* @author alteredq / http://alteredqualia.com/
*/
THREE.EffectComposer = function ( renderer, renderTarget ) {
this.renderer = renderer;
if ( renderTarget === undefined ) {
var parameters = {
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
format: THREE.RGBAFormat,
stencilBuffer: false,
//type: THREE.FloatType
type: THREE.UnsignedShortType,
};
var size = new THREE.Vector2();
renderer.getDrawingBufferSize(size);
renderTarget = new THREE.WebGLRenderTarget( size.x, size.y, parameters );
renderTarget.texture.name = 'EffectComposer.rt1';
}
this.renderTarget1 = renderTarget;
this.renderTarget2 = renderTarget.clone();
this.renderTarget2.texture.name = 'EffectComposer.rt2';
this.writeBuffer = this.renderTarget1;
this.readBuffer = this.renderTarget2;
this.passes = [];
// dependencies
if ( THREE.CopyShader === undefined ) {
console.error( 'THREE.EffectComposer relies on THREE.CopyShader' );
}
if ( THREE.ShaderPass === undefined ) {
console.error( 'THREE.EffectComposer relies on THREE.ShaderPass' );
}
this.copyPass = new THREE.ShaderPass( THREE.CopyShader );
};
Object.assign( THREE.EffectComposer.prototype, {
swapBuffers: function () {
var tmp = this.readBuffer;
this.readBuffer = this.writeBuffer;
this.writeBuffer = tmp;
},
addPass: function ( pass ) {
this.passes.push( pass );
var size = new THREE.Vector2();
this.renderer.getDrawingBufferSize(size);
pass.setSize( size.x, size.y );
},
insertPass: function ( pass, index ) {
this.passes.splice( index, 0, pass );
},
render: function ( delta ) {
var maskActive = false;
var pass, i, il = this.passes.length;
for ( i = 0; i < il; i ++ ) {
pass = this.passes[ i ];
if ( pass.enabled === false ) continue;
pass.render( this.renderer, this.writeBuffer, this.readBuffer, delta, maskActive );
if ( pass.needsSwap ) {
if ( maskActive ) {
var context = this.renderer.context;
context.stencilFunc( context.NOTEQUAL, 1, 0xffffffff );
this.copyPass.render( this.renderer, this.writeBuffer, this.readBuffer, delta );
context.stencilFunc( context.EQUAL, 1, 0xffffffff );
}
this.swapBuffers();
}
if ( THREE.MaskPass !== undefined ) {
if ( pass instanceof THREE.MaskPass ) {
maskActive = true;
} else if ( pass instanceof THREE.ClearMaskPass ) {
maskActive = false;
}
}
}
},
reset: function ( renderTarget ) {
if ( renderTarget === undefined ) {
var size = new THREE.Vector2();
this.renderer.getDrawingBufferSize(size);
renderTarget = this.renderTarget1.clone();
renderTarget.setSize( size.x, size.y );
}
this.renderTarget1.dispose();
this.renderTarget2.dispose();
this.renderTarget1 = renderTarget;
this.renderTarget2 = renderTarget.clone();
this.writeBuffer = this.renderTarget1;
this.readBuffer = this.renderTarget2;
},
setSize: function ( width, height ) {
this.renderTarget1.setSize( width, height );
this.renderTarget2.setSize( width, height );
for ( var i = 0; i < this.passes.length; i ++ ) {
this.passes[ i ].setSize( width, height );
}
}
} );
THREE.Pass = function () {
// if set to true, the pass is processed by the composer
this.enabled = true;
// if set to true, the pass indicates to swap read and write buffer after rendering
this.needsSwap = true;
// if set to true, the pass clears its buffer before rendering
this.clear = false;
// if set to true, the result of the pass is rendered to screen
this.renderToScreen = false;
};
Object.assign( THREE.Pass.prototype, {
setSize: function ( width, height ) {},
render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
console.error( 'THREE.Pass: .render() must be implemented in derived pass.' );
}
} );
// Helper for passes that need to fill the viewport with a single quad.
THREE.Pass.FullScreenQuad = ( function () {
var camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
var geometry = new THREE.PlaneGeometry( 2, 2 );
var FullScreenQuad = function ( material ) {
this._mesh = new THREE.Mesh( geometry, material );
};
Object.defineProperty( FullScreenQuad.prototype, 'material', {
get: function () {
return this._mesh.material;
},
set: function ( value ) {
this._mesh.material = value;
}
} );
Object.assign( FullScreenQuad.prototype, {
dispose: function () {
this._mesh.geometry.dispose();
},
render: function ( renderer ) {
renderer.render( this._mesh, camera );
}
} );
return FullScreenQuad;
} )();
/**
* @author alteredq / http://alteredqualia.com/
*/
THREE.RenderPass = function ( scene, camera, overrideMaterial, clearColor, clearAlpha ) {
THREE.Pass.call( this );
this.scene = scene;
this.camera = camera;
this.overrideMaterial = overrideMaterial;
this.clearColor = clearColor;
this.clearAlpha = ( clearAlpha !== undefined ) ? clearAlpha : 0;
this.clear = true;
this.clearDepth = false;
this.needsSwap = false;
};
THREE.RenderPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.RenderPass,
render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
var oldAutoClear = renderer.autoClear;
renderer.autoClear = false;
this.scene.overrideMaterial = this.overrideMaterial;
var oldClearColor, oldClearAlpha;
if ( this.clearColor ) {
oldClearColor = renderer.getClearColor().getHex();
oldClearAlpha = renderer.getClearAlpha();
renderer.setClearColor( this.clearColor, this.clearAlpha );
}
if ( this.clearDepth ) {
renderer.clearDepth();
}
renderer.setRenderTarget(this.renderToScreen ? null : readBuffer);
if (this.clear) renderer.clear();
renderer.render( this.scene, this.camera);
if ( this.clearColor ) {
renderer.setClearColor( oldClearColor, oldClearAlpha );
}
this.scene.overrideMaterial = null;
renderer.autoClear = oldAutoClear;
}
} );
/**
* @author alteredq / http://alteredqualia.com/
*/
THREE.ShaderPass = function ( shader, textureID ) {
THREE.Pass.call( this );
this.textureID = ( textureID !== undefined ) ? textureID : "tDiffuse";
if ( shader instanceof THREE.ShaderMaterial ) {
this.uniforms = shader.uniforms;
this.material = shader;
} else if ( shader ) {
this.uniforms = THREE.UniformsUtils.clone( shader.uniforms );
this.material = new THREE.ShaderMaterial( {
defines: Object.assign( {}, shader.defines ),
uniforms: this.uniforms,
vertexShader: shader.vertexShader,
fragmentShader: shader.fragmentShader
} );
}
this.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
this.scene = new THREE.Scene();
this.quad = new THREE.Mesh( new THREE.PlaneGeometry( 2, 2 ), null );
this.quad.frustumCulled = false; // Avoid getting clipped
this.scene.add( this.quad );
};
THREE.ShaderPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.ShaderPass,
render: function( renderer, writeBuffer, readBuffer, delta, maskActive ) {
if ( this.uniforms[ this.textureID ] ) {
this.uniforms[ this.textureID ].value = readBuffer.texture;
}
this.quad.material = this.material;
renderer.setRenderTarget(this.renderToScreen ? null : writeBuffer);
if (this.clear) renderer.clear();
renderer.render( this.scene, this.camera);
}
} );
/**
* @author alteredq / http://alteredqualia.com/
*/
THREE.MaskPass = function ( scene, camera ) {
THREE.Pass.call( this );
this.scene = scene;
this.camera = camera;
this.clear = true;
this.needsSwap = false;
this.inverse = false;
};
THREE.MaskPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.MaskPass,
render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
var context = renderer.context;
var state = renderer.state;
// don't update color or depth
state.buffers.color.setMask( false );
state.buffers.depth.setMask( false );
// lock buffers
state.buffers.color.setLocked( true );
state.buffers.depth.setLocked( true );
// set up stencil
var writeValue, clearValue;
if ( this.inverse ) {
writeValue = 0;
clearValue = 1;
} else {
writeValue = 1;
clearValue = 0;
}
state.buffers.stencil.setTest( true );
state.buffers.stencil.setOp( context.REPLACE, context.REPLACE, context.REPLACE );
state.buffers.stencil.setFunc( context.ALWAYS, writeValue, 0xffffffff );
state.buffers.stencil.setClear( clearValue );
// draw into the stencil buffer
renderer.setRenderTarget(readBuffer);
if (this.clear) renderer.clear();
renderer.render( this.scene, this.camera);
renderer.setRenderTarget(writeBuffer);
if (this.clear) renderer.clear();
renderer.render( this.scene, this.camera );
// unlock color and depth buffer for subsequent rendering
state.buffers.color.setLocked( false );
state.buffers.depth.setLocked( false );
// only render where stencil is set to 1
state.buffers.stencil.setFunc( context.EQUAL, 1, 0xffffffff ); // draw if == 1
state.buffers.stencil.setOp( context.KEEP, context.KEEP, context.KEEP );
}
} );
THREE.ClearMaskPass = function () {
THREE.Pass.call( this );
this.needsSwap = false;
};
THREE.ClearMaskPass.prototype = Object.create( THREE.Pass.prototype );
Object.assign( THREE.ClearMaskPass.prototype, {
render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
renderer.state.buffers.stencil.setTest( false );
}
} );
/**
* @author alteredq / http://alteredqualia.com/
*/
THREE.BloomPass = function ( strength, kernelSize, sigma, resolution ) {
THREE.Pass.call( this );
strength = ( strength !== undefined ) ? strength : 1;
kernelSize = ( kernelSize !== undefined ) ? kernelSize : 25;
sigma = ( sigma !== undefined ) ? sigma : 4.0;
resolution = ( resolution !== undefined ) ? resolution : 256;
// render targets
var pars = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat };
this.renderTargetX = new THREE.WebGLRenderTarget( resolution, resolution, pars );
this.renderTargetX.texture.name = "BloomPass.x";
this.renderTargetY = new THREE.WebGLRenderTarget( resolution, resolution, pars );
this.renderTargetY.texture.name = "BloomPass.y";
// copy material
if ( THREE.CopyShader === undefined )
console.error( "THREE.BloomPass relies on THREE.CopyShader" );
var copyShader = THREE.CopyShader;
this.copyUniforms = THREE.UniformsUtils.clone( copyShader.uniforms );
this.copyUniforms[ "opacity" ].value = strength;
this.materialCopy = new THREE.ShaderMaterial( {
uniforms: this.copyUniforms,
vertexShader: copyShader.vertexShader,
fragmentShader: copyShader.fragmentShader,
blending: THREE.AdditiveBlending,
transparent: true
} );
// convolution material
if ( THREE.ConvolutionShader === undefined )
console.error( "THREE.BloomPass relies on THREE.ConvolutionShader" );
var convolutionShader = THREE.ConvolutionShader;
this.convolutionUniforms = THREE.UniformsUtils.clone( convolutionShader.uniforms );
this.convolutionUniforms[ "uImageIncrement" ].value = THREE.BloomPass.blurX;
this.convolutionUniforms[ "cKernel" ].value = THREE.ConvolutionShader.buildKernel( sigma );
this.materialConvolution = new THREE.ShaderMaterial( {
uniforms: this.convolutionUniforms,
vertexShader: convolutionShader.vertexShader,
fragmentShader: convolutionShader.fragmentShader,
defines: {
"KERNEL_SIZE_FLOAT": kernelSize.toFixed( 1 ),
"KERNEL_SIZE_INT": kernelSize.toFixed( 0 )
}
} );
this.needsSwap = false;
this.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
this.scene = new THREE.Scene();
this.quad = new THREE.Mesh( new THREE.PlaneGeometry( 2, 2 ), null );
this.quad.frustumCulled = false; // Avoid getting clipped
this.scene.add( this.quad );
};
THREE.BloomPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.BloomPass,
render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
if ( maskActive ) renderer.context.disable( renderer.context.STENCIL_TEST );
// Render quad with blured scene into texture (convolution pass 1)
this.quad.material = this.materialConvolution;
this.convolutionUniforms[ "tDiffuse" ].value = readBuffer.texture;
this.convolutionUniforms[ "uImageIncrement" ].value = THREE.BloomPass.blurX;
renderer.setRenderTarget(this.renderTargetX);
renderer.clear();
renderer.render( this.scene, this.camera );
// Render quad with blured scene into texture (convolution pass 2)
this.convolutionUniforms[ "tDiffuse" ].value = this.renderTargetX.texture;
this.convolutionUniforms[ "uImageIncrement" ].value = THREE.BloomPass.blurY;
renderer.setRenderTarget(this.renderTargetY);
renderer.clear();
renderer.render( this.scene, this.camera );
// Render original scene with superimposed blur to texture
this.quad.material = this.materialCopy;
this.copyUniforms[ "tDiffuse" ].value = this.renderTargetY.texture;
if ( maskActive ) renderer.context.enable( renderer.context.STENCIL_TEST );
renderer.setRenderTarget(readBuffer);
if (this.clear) renderer.clear();
renderer.render( this.scene, this.camera );
}
} );
THREE.BloomPass.blurX = new THREE.Vector2( 0.001953125, 0.0 );
THREE.BloomPass.blurY = new THREE.Vector2( 0.0, 0.001953125 );
/**
* @author mrdoob / http://mrdoob.com/
*/
THREE.ClearPass = function ( clearColor, clearAlpha ) {
THREE.Pass.call( this );
this.needsSwap = false;
this.clearColor = ( clearColor !== undefined ) ? clearColor : 0x000000;
this.clearAlpha = ( clearAlpha !== undefined ) ? clearAlpha : 0;
};
THREE.ClearPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.ClearPass,
render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
var oldClearColor, oldClearAlpha;
if ( this.clearColor ) {
oldClearColor = renderer.getClearColor().getHex();
oldClearAlpha = renderer.getClearAlpha();
renderer.setClearColor( this.clearColor, this.clearAlpha );
}
renderer.setRenderTarget( this.renderToScreen ? null : readBuffer );
renderer.clear();
if ( this.clearColor ) {
renderer.setClearColor( oldClearColor, oldClearAlpha );
}
}
} );
/**
* @author miibond
* Generate a texture that represents the luminosity of the current scene, adapted over time
* to simulate the optic nerve responding to the amount of light it is receiving.
* Based on a GDC2007 presentation by Wolfgang Engel titled "Post-Processing Pipeline"
*
* Full-screen tone-mapping shader based on http://www.graphics.cornell.edu/~jaf/publications/sig02_paper.pdf
*/
THREE.AdaptiveToneMappingPass = function ( adaptive, resolution ) {
THREE.Pass.call( this );
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 ( THREE.CopyShader === undefined )
console.error( "THREE.AdaptiveToneMappingPass relies on THREE.CopyShader" );
var copyShader = THREE.CopyShader;
this.copyUniforms = THREE.UniformsUtils.clone( copyShader.uniforms );
this.materialCopy = new THREE.ShaderMaterial( {
uniforms: this.copyUniforms,
vertexShader: copyShader.vertexShader,
fragmentShader: copyShader.fragmentShader,
blending: THREE.NoBlending,
depthTest: false
} );
if ( THREE.LuminosityShader === undefined )
console.error( "THREE.AdaptiveToneMappingPass relies on THREE.LuminosityShader" );
this.materialLuminance = new THREE.ShaderMaterial( {
uniforms: THREE.UniformsUtils.clone( THREE.LuminosityShader.uniforms ),
vertexShader: THREE.LuminosityShader.vertexShader,
fragmentShader: THREE.LuminosityShader.fragmentShader,
blending: THREE.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 THREE.ShaderMaterial( {
uniforms: THREE.UniformsUtils.clone( this.adaptLuminanceShader.uniforms ),
vertexShader: this.adaptLuminanceShader.vertexShader,
fragmentShader: this.adaptLuminanceShader.fragmentShader,
defines: Object.assign( {}, this.adaptLuminanceShader.defines ),
blending: THREE.NoBlending
} );
if ( THREE.ToneMapShader === undefined )
console.error( "THREE.AdaptiveToneMappingPass relies on THREE.ToneMapShader" );
this.materialToneMap = new THREE.ShaderMaterial( {
uniforms: THREE.UniformsUtils.clone( THREE.ToneMapShader.uniforms ),
vertexShader: THREE.ToneMapShader.vertexShader,
fragmentShader: THREE.ToneMapShader.fragmentShader,
blending: THREE.NoBlending
} );
this.fsQuad = new THREE.Pass.FullScreenQuad( null );
};
THREE.AdaptiveToneMappingPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.AdaptiveToneMappingPass,
render: function ( renderer, writeBuffer, readBuffer, deltaTime/*, maskActive*/ ) {
if ( this.needsInit ) {
this.reset( renderer );
this.luminanceRT.texture.type = readBuffer.texture.type;
this.previousLuminanceRT.texture.type = readBuffer.texture.type;
this.currentLuminanceRT.texture.type = readBuffer.texture.type;
this.needsInit = false;
}
if ( this.adaptive ) {
//Render the luminance of the current scene into a render target with mipmapping enabled
this.fsQuad.material = this.materialLuminance;
this.materialLuminance.uniforms.tDiffuse.value = readBuffer.texture;
renderer.setRenderTarget( this.currentLuminanceRT );
this.fsQuad.render( renderer );
//Use the new luminance values, the previous luminance and the frame delta to
//adapt the luminance over time.
this.fsQuad.material = this.materialAdaptiveLum;
this.materialAdaptiveLum.uniforms.delta.value = deltaTime;
this.materialAdaptiveLum.uniforms.lastLum.value = this.previousLuminanceRT.texture;
this.materialAdaptiveLum.uniforms.currentLum.value = this.currentLuminanceRT.texture;
renderer.setRenderTarget( this.luminanceRT );
this.fsQuad.render( renderer );
//Copy the new adapted luminance value so that it can be used by the next frame.
this.fsQuad.material = this.materialCopy;
this.copyUniforms.tDiffuse.value = this.luminanceRT.texture;
renderer.setRenderTarget( this.previousLuminanceRT );
this.fsQuad.render( renderer );
}
this.fsQuad.material = this.materialToneMap;
this.materialToneMap.uniforms.tDiffuse.value = readBuffer.texture;
if ( this.renderToScreen ) {
renderer.setRenderTarget( null );
this.fsQuad.render( renderer );
} else {
renderer.setRenderTarget( writeBuffer );
if ( this.clear ) renderer.clear();
this.fsQuad.render( renderer );
}
},
reset: function () {
// render targets
if ( this.luminanceRT ) {
this.luminanceRT.dispose();
}
if ( this.currentLuminanceRT ) {
this.currentLuminanceRT.dispose();
}
if ( this.previousLuminanceRT ) {
this.previousLuminanceRT.dispose();
}
var pars = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat }; // was RGB format. changed to RGBA format. see discussion in #8415 / #8450
this.luminanceRT = new THREE.WebGLRenderTarget( this.resolution, this.resolution, pars );
this.luminanceRT.texture.name = "AdaptiveToneMappingPass.l";
this.luminanceRT.texture.generateMipmaps = false;
this.previousLuminanceRT = new THREE.WebGLRenderTarget( this.resolution, this.resolution, pars );
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 = THREE.LinearMipmapLinearFilter;
pars.generateMipmaps = true;
this.currentLuminanceRT = new THREE.WebGLRenderTarget( this.resolution, this.resolution, pars );
this.currentLuminanceRT.texture.name = "AdaptiveToneMappingPass.cl";
if ( this.adaptive ) {
this.materialToneMap.defines[ "ADAPTED_LUMINANCE" ] = "";
this.materialToneMap.uniforms.luminanceMap.value = this.luminanceRT.texture;
}
//Put something in the adaptive luminance texture so that the scene can render initially
this.fsQuad.material = new THREE.MeshBasicMaterial( { color: 0x777777 } );
this.materialLuminance.needsUpdate = true;
this.materialAdaptiveLum.needsUpdate = true;
this.materialToneMap.needsUpdate = true;
// 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 ) {
if ( adaptive ) {
this.adaptive = true;
this.materialToneMap.defines[ "ADAPTED_LUMINANCE" ] = "";
this.materialToneMap.uniforms.luminanceMap.value = this.luminanceRT.texture;
} else {
this.adaptive = false;
delete this.materialToneMap.defines[ "ADAPTED_LUMINANCE" ];
this.materialToneMap.uniforms.luminanceMap.value = null;
}
this.materialToneMap.needsUpdate = true;
},
setAdaptionRate: function ( rate ) {
if ( rate ) {
this.materialAdaptiveLum.uniforms.tau.value = Math.abs( rate );
}
},
setMinLuminance: function ( minLum ) {
if ( minLum ) {
this.materialToneMap.uniforms.minLuminance.value = minLum;
this.materialAdaptiveLum.uniforms.minLuminance.value = minLum;
}
},
setMaxLuminance: function ( maxLum ) {
if ( maxLum ) {
this.materialToneMap.uniforms.maxLuminance.value = maxLum;
}
},
setAverageLuminance: function ( avgLum ) {
if ( avgLum ) {
this.materialToneMap.uniforms.averageLuminance.value = avgLum;
}
},
setMiddleGrey: function ( middleGrey ) {
if ( middleGrey ) {
this.materialToneMap.uniforms.middleGrey.value = middleGrey;
}
},
dispose: function () {
if ( this.luminanceRT ) {
this.luminanceRT.dispose();
}
if ( this.previousLuminanceRT ) {
this.previousLuminanceRT.dispose();
}
if ( this.currentLuminanceRT ) {
this.currentLuminanceRT.dispose();
}
if ( this.materialLuminance ) {
this.materialLuminance.dispose();
}
if ( this.materialAdaptiveLum ) {
this.materialAdaptiveLum.dispose();
}
if ( this.materialCopy ) {
this.materialCopy.dispose();
}
if ( this.materialToneMap ) {
this.materialToneMap.dispose();
}
}
} );
/**
* @author spidersharma / http://eduperiment.com/
*/
/**
* UnrealBloomPass is inspired by the bloom pass of Unreal Engine. It creates a
* mip map chain of bloom textures and blurs them with different radii. Because
* of the weighted combination of mips, and because larger blurs are done on
* higher mips, this effect provides good quality and performance.
*
* Reference:
* - https://docs.unrealengine.com/latest/INT/Engine/Rendering/PostProcessEffects/Bloom/
*/
THREE.UnrealBloomPass = function ( resolution, strength, radius, threshold ) {
THREE.Pass.call( this );
this.strength = ( strength !== undefined ) ? strength : 1;
this.radius = radius;
this.threshold = threshold;
this.resolution = ( resolution !== undefined ) ? new THREE.Vector2( resolution.x, resolution.y ) : new THREE.Vector2( 256, 256 );
// create color only once here, reuse it later inside the render function
this.clearColor = new THREE.Color( 0, 0, 0 );
// render targets
var pars = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat };
this.renderTargetsHorizontal = [];
this.renderTargetsVertical = [];
this.nMips = 5;
var resx = Math.round( this.resolution.x / 2 );
var resy = Math.round( this.resolution.y / 2 );
this.renderTargetBright = new THREE.WebGLRenderTarget( resx, resy, pars );
this.renderTargetBright.texture.name = "UnrealBloomPass.bright";
this.renderTargetBright.texture.generateMipmaps = false;
for ( var i = 0; i < this.nMips; i ++ ) {
var renderTargetHorizonal = new THREE.WebGLRenderTarget( resx, resy, pars );
renderTargetHorizonal.texture.name = "UnrealBloomPass.h" + i;
renderTargetHorizonal.texture.generateMipmaps = false;
this.renderTargetsHorizontal.push( renderTargetHorizonal );
var renderTargetVertical = new THREE.WebGLRenderTarget( resx, resy, pars );
renderTargetVertical.texture.name = "UnrealBloomPass.v" + i;
renderTargetVertical.texture.generateMipmaps = false;
this.renderTargetsVertical.push( renderTargetVertical );
resx = Math.round( resx / 2 );
resy = Math.round( resy / 2 );
}
// luminosity high pass material
if ( THREE.LuminosityHighPassShader === undefined )
console.error( "THREE.UnrealBloomPass relies on THREE.LuminosityHighPassShader" );
var highPassShader = THREE.LuminosityHighPassShader;
this.highPassUniforms = THREE.UniformsUtils.clone( highPassShader.uniforms );
this.highPassUniforms[ "luminosityThreshold" ].value = threshold;
this.highPassUniforms[ "smoothWidth" ].value = 0.01;
this.materialHighPassFilter = new THREE.ShaderMaterial( {
uniforms: this.highPassUniforms,
vertexShader: highPassShader.vertexShader,
fragmentShader: highPassShader.fragmentShader,
defines: {}
} );
// 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 );
for ( var i = 0; i < this.nMips; i ++ ) {
this.separableBlurMaterials.push( this.getSeperableBlurMaterial( kernelSizeArray[ i ] ) );
this.separableBlurMaterials[ i ].uniforms[ "texSize" ].value = new THREE.Vector2( resx, resy );
resx = Math.round( resx / 2 );
resy = Math.round( resy / 2 );
}
// 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 THREE.Vector3( 1, 1, 1 ), new THREE.Vector3( 1, 1, 1 ), new THREE.Vector3( 1, 1, 1 ),
new THREE.Vector3( 1, 1, 1 ), new THREE.Vector3( 1, 1, 1 ) ];
this.compositeMaterial.uniforms[ "bloomTintColors" ].value = this.bloomTintColors;
// copy material
if ( THREE.CopyShader === undefined ) {
console.error( "THREE.UnrealBloomPass relies on THREE.CopyShader" );
}
var copyShader = THREE.CopyShader;
this.copyUniforms = THREE.UniformsUtils.clone( copyShader.uniforms );
this.copyUniforms[ "opacity" ].value = 1.0;
this.materialCopy = new THREE.ShaderMaterial( {
uniforms: this.copyUniforms,
vertexShader: copyShader.vertexShader,
fragmentShader: copyShader.fragmentShader,
blending: THREE.AdditiveBlending,
depthTest: false,
depthWrite: false,
transparent: true
} );
this.enabled = true;
this.needsSwap = false;
this.oldClearColor = new THREE.Color();
this.oldClearAlpha = 1;
this.basic = new THREE.MeshBasicMaterial();
this.fsQuad = new THREE.Pass.FullScreenQuad( null );
};
THREE.UnrealBloomPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.UnrealBloomPass,
dispose: function () {
for ( var i = 0; i < this.renderTargetsHorizontal.length; i ++ ) {
this.renderTargetsHorizontal[ i ].dispose();
}
for ( var i = 0; i < this.renderTargetsVertical.length; i ++ ) {
this.renderTargetsVertical[ i ].dispose();
}
this.renderTargetBright.dispose();
},
setSize: function ( width, height ) {
var resx = Math.round( width / 2 );
var resy = Math.round( height / 2 );
this.renderTargetBright.setSize( resx, resy );
for ( var i = 0; i < this.nMips; i ++ ) {
this.renderTargetsHorizontal[ i ].setSize( resx, resy );
this.renderTargetsVertical[ i ].setSize( resx, resy );
this.separableBlurMaterials[ i ].uniforms[ "texSize" ].value = new THREE.Vector2( resx, resy );
resx = Math.round( resx / 2 );
resy = Math.round( resy / 2 );
}
},
render: function ( renderer, writeBuffer, readBuffer, deltaTime, maskActive ) {
renderer.getClearColor(this.oldClearColor);
this.oldClearAlpha = renderer.getClearAlpha();
var oldAutoClear = renderer.autoClear;
renderer.autoClear = false;
renderer.setClearColor( this.clearColor, 0 );
if ( maskActive ) renderer.state.buffers.stencil.setTest( false );
// Render input to screen
if ( this.renderToScreen ) {
this.fsQuad.material = this.basic;
this.basic.map = readBuffer.texture;
renderer.setRenderTarget( null );
renderer.clear();
this.fsQuad.render( renderer );
}
// 1. Extract Bright Areas
this.highPassUniforms[ "tDiffuse" ].value = readBuffer.texture;
this.highPassUniforms[ "luminosityThreshold" ].value = this.threshold;
this.fsQuad.material = this.materialHighPassFilter;
renderer.setRenderTarget( this.renderTargetBright );
renderer.clear();
this.fsQuad.render( renderer );
// 2. Blur All the mips progressively
var inputRenderTarget = this.renderTargetBright;
for ( var i = 0; i < this.nMips; i ++ ) {
this.fsQuad.material = this.separableBlurMaterials[ i ];
this.separableBlurMaterials[ i ].uniforms[ "colorTexture" ].value = inputRenderTarget.texture;
this.separableBlurMaterials[ i ].uniforms[ "direction" ].value = THREE.UnrealBloomPass.BlurDirectionX;
renderer.setRenderTarget( this.renderTargetsHorizontal[ i ] );
renderer.clear();
this.fsQuad.render( renderer );
this.separableBlurMaterials[ i ].uniforms[ "colorTexture" ].value = this.renderTargetsHorizontal[ i ].texture;
this.separableBlurMaterials[ i ].uniforms[ "direction" ].value = THREE.UnrealBloomPass.BlurDirectionY;
renderer.setRenderTarget( this.renderTargetsVertical[ i ] );
renderer.clear();
this.fsQuad.render( renderer );
inputRenderTarget = this.renderTargetsVertical[ i ];
}
// Composite All the mips
this.fsQuad.material = this.compositeMaterial;
this.compositeMaterial.uniforms[ "bloomStrength" ].value = this.strength;
this.compositeMaterial.uniforms[ "bloomRadius" ].value = this.radius;
this.compositeMaterial.uniforms[ "bloomTintColors" ].value = this.bloomTintColors;
renderer.setRenderTarget( this.renderTargetsHorizontal[ 0 ] );
renderer.clear();
this.fsQuad.render( renderer );
// Blend it additively over the input texture
this.fsQuad.material = this.materialCopy;
this.copyUniforms[ "tDiffuse" ].value = this.renderTargetsHorizontal[ 0 ].texture;
if ( maskActive ) renderer.state.buffers.stencil.setTest( true );
if ( this.renderToScreen ) {
renderer.setRenderTarget( null );
this.fsQuad.render( renderer );
} else {
renderer.setRenderTarget( readBuffer );
this.fsQuad.render( renderer );
}
// Restore renderer settings
renderer.setClearColor( this.oldClearColor, this.oldClearAlpha );
renderer.autoClear = oldAutoClear;
},
getSeperableBlurMaterial: function ( kernelRadius ) {
return new THREE.ShaderMaterial( {
defines: {
"KERNEL_RADIUS": kernelRadius,
"SIGMA": kernelRadius
},
uniforms: {
"colorTexture": { value: null },
"texSize": { value: new THREE.Vector2( 0.5, 0.5 ) },
"direction": { value: new THREE.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 <common>\
varying vec2 vUv;\n\
uniform sampler2D colorTexture;\n\
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() {\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\
}"
} );
},
getCompositeMaterial: function ( nMips ) {
return new THREE.ShaderMaterial( {
defines: {
"NUM_MIPS": nMips
},
uniforms: {
"blurTexture1": { value: null },
"blurTexture2": { value: null },
"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) );\
}"
} );
}
} );
THREE.UnrealBloomPass.BlurDirectionX = new THREE.Vector2( 1.0, 0.0 );
THREE.UnrealBloomPass.BlurDirectionY = new THREE.Vector2( 0.0, 1.0 );
/**
* @author Mugen87 / https://github.com/Mugen87
*/
THREE.SSAOPass = function ( scene, camera, width, height ) {
THREE.Pass.call( this );
this.width = ( width !== undefined ) ? width : 512;
this.height = ( height !== undefined ) ? height : 512;
this.clear = true;
this.camera = camera;
this.scene = scene;
this.kernelRadius = 8;
this.kernelSize = 32;
this.kernel = [];
this.noiseTexture = null;
this.output = 0;
this.minDistance = 0.005;
this.maxDistance = 0.1;
//
this.generateSampleKernel();
this.generateRandomKernelRotations();
// beauty render target with depth buffer
var depthTexture = new THREE.DepthTexture();
depthTexture.type = THREE.UnsignedInt248Type;
depthTexture.format = THREE.DepthStencilFormat;
depthTexture.minFilter = THREE.NearestFilter;
depthTexture.maxFilter = THREE.NearestFilter;
this.beautyRenderTarget = new THREE.WebGLRenderTarget( this.width, this.height, {
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
format: THREE.RGBAFormat,
depthTexture: depthTexture,
depthBuffer: true
} );
// normal render target
this.normalRenderTarget = new THREE.WebGLRenderTarget( this.width, this.height, {
minFilter: THREE.NearestFilter,
magFilter: THREE.NearestFilter,
format: THREE.RGBAFormat
} );
// ssao render target
this.ssaoRenderTarget = new THREE.WebGLRenderTarget( this.width, this.height, {
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
format: THREE.RGBAFormat
} );
this.blurRenderTarget = this.ssaoRenderTarget.clone();
// ssao material
if ( THREE.SSAOShader === undefined ) {
console.error( 'THREE.SSAOPass: The pass relies on THREE.SSAOShader.' );
}
this.ssaoMaterial = new THREE.ShaderMaterial( {
defines: Object.assign( {}, THREE.SSAOShader.defines ),
uniforms: THREE.UniformsUtils.clone( THREE.SSAOShader.uniforms ),
vertexShader: THREE.SSAOShader.vertexShader,
fragmentShader: THREE.SSAOShader.fragmentShader,
blending: THREE.NoBlending
} );
this.ssaoMaterial.uniforms[ 'tDiffuse' ].value = this.beautyRenderTarget.texture;
this.ssaoMaterial.uniforms[ 'tNormal' ].value = this.normalRenderTarget.texture;
this.ssaoMaterial.uniforms[ 'tDepth' ].value = this.beautyRenderTarget.depthTexture;
this.ssaoMaterial.uniforms[ 'tNoise' ].value = this.noiseTexture;
this.ssaoMaterial.uniforms[ 'kernel' ].value = this.kernel;
this.ssaoMaterial.uniforms[ 'cameraNear' ].value = this.camera.near;
this.ssaoMaterial.uniforms[ 'cameraFar' ].value = this.camera.far;
this.ssaoMaterial.uniforms[ 'resolution' ].value.set( this.width, this.height );
this.ssaoMaterial.uniforms[ 'cameraProjectionMatrix' ].value.copy( this.camera.projectionMatrix );
this.ssaoMaterial.uniforms[ 'cameraInverseProjectionMatrix' ].value.getInverse( this.camera.projectionMatrix );
// normal material
this.normalMaterial = new THREE.MeshNormalMaterial();
this.normalMaterial.blending = THREE.NoBlending;
// blur material
this.blurMaterial = new THREE.ShaderMaterial( {
defines: Object.assign( {}, THREE.SSAOBlurShader.defines ),
uniforms: THREE.UniformsUtils.clone( THREE.SSAOBlurShader.uniforms ),
vertexShader: THREE.SSAOBlurShader.vertexShader,
fragmentShader: THREE.SSAOBlurShader.fragmentShader
} );
this.blurMaterial.uniforms[ 'tDiffuse' ].value = this.ssaoRenderTarget.texture;
this.blurMaterial.uniforms[ 'resolution' ].value.set( this.width, this.height );
// material for rendering the depth
this.depthRenderMaterial = new THREE.ShaderMaterial( {
defines: Object.assign( {}, THREE.SSAODepthShader.defines ),
uniforms: THREE.UniformsUtils.clone( THREE.SSAODepthShader.uniforms ),
vertexShader: THREE.SSAODepthShader.vertexShader,
fragmentShader: THREE.SSAODepthShader.fragmentShader,
blending: THREE.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 THREE.ShaderMaterial( {
uniforms: THREE.UniformsUtils.clone( THREE.CopyShader.uniforms ),
vertexShader: THREE.CopyShader.vertexShader,
fragmentShader: THREE.CopyShader.fragmentShader,
transparent: true,
depthTest: false,
depthWrite: false,
blendSrc: THREE.DstColorFactor,
blendDst: THREE.ZeroFactor,
blendEquation: THREE.AddEquation,
blendSrcAlpha: THREE.DstAlphaFactor,
blendDstAlpha: THREE.ZeroFactor,
blendEquationAlpha: THREE.AddEquation
} );
this.fsQuad = new THREE.Pass.FullScreenQuad( null );
this.originalClearColor = new THREE.Color();
};
THREE.SSAOPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.SSAOPass,
dispose: function () {
// dispose render targets
this.beautyRenderTarget.dispose();
this.normalRenderTarget.dispose();
this.ssaoRenderTarget.dispose();
this.blurRenderTarget.dispose();
// dispose materials
this.normalMaterial.dispose();
this.blurMaterial.dispose();
this.copyMaterial.dispose();
this.depthRenderMaterial.dispose();
// dipsose full screen quad
this.fsQuad.dispose();
},
render: function ( renderer, writeBuffer /*, readBuffer, deltaTime, maskActive */ ) {
// render beauty and depth
renderer.setRenderTarget( this.beautyRenderTarget );
renderer.clear();
renderer.render( this.scene, this.camera );
// render normals
this.renderOverride( renderer, this.normalMaterial, this.normalRenderTarget, 0x7777ff, 1.0 );
// render SSAO
this.ssaoMaterial.uniforms[ 'kernelRadius' ].value = this.kernelRadius;
this.ssaoMaterial.uniforms[ 'minDistance' ].value = this.minDistance;
this.ssaoMaterial.uniforms[ 'maxDistance' ].value = this.maxDistance;
this.renderPass( renderer, this.ssaoMaterial, this.ssaoRenderTarget );
// render blur
this.renderPass( renderer, this.blurMaterial, this.blurRenderTarget );
// output result to screen
switch ( this.output ) {
case THREE.SSAOPass.OUTPUT.SSAO:
this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.ssaoRenderTarget.texture;
this.copyMaterial.blending = THREE.NoBlending;
this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer );
break;
case THREE.SSAOPass.OUTPUT.Blur:
this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.blurRenderTarget.texture;
this.copyMaterial.blending = THREE.NoBlending;
this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer );
break;
case THREE.SSAOPass.OUTPUT.Beauty:
this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.beautyRenderTarget.texture;
this.copyMaterial.blending = THREE.NoBlending;
this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer );
break;
case THREE.SSAOPass.OUTPUT.Depth:
this.renderPass( renderer, this.depthRenderMaterial, this.renderToScreen ? null : writeBuffer );
break;
case THREE.SSAOPass.OUTPUT.Normal:
this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.normalRenderTarget.texture;
this.copyMaterial.blending = THREE.NoBlending;
this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer );
break;
case THREE.SSAOPass.OUTPUT.Default:
this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.beautyRenderTarget.texture;
this.copyMaterial.blending = THREE.NoBlending;
this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer );
this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.blurRenderTarget.texture;
this.copyMaterial.blending = THREE.CustomBlending;
this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer );
break;
default:
console.warn( 'THREE.SSAOPass: Unknown output type.' );
}
},
renderPass: function ( renderer, passMaterial, renderTarget, clearColor, clearAlpha ) {
// save original state
this.originalClearColor.copy( renderer.getClearColor() );
var originalClearAlpha = renderer.getClearAlpha();
var originalAutoClear = renderer.autoClear;
renderer.setRenderTarget( renderTarget );
// setup pass state
renderer.autoClear = false;
if ( ( clearColor !== undefined ) && ( clearColor !== null ) ) {
renderer.setClearColor( clearColor );
renderer.setClearAlpha( clearAlpha || 0.0 );
renderer.clear();
}
this.fsQuad.material = passMaterial;
this.fsQuad.render( renderer );
// restore original state
renderer.autoClear = originalAutoClear;
renderer.setClearColor( this.originalClearColor );
renderer.setClearAlpha( originalClearAlpha );
},
renderOverride: function ( renderer, overrideMaterial, renderTarget, clearColor, clearAlpha ) {
this.originalClearColor.copy( renderer.getClearColor() );
var originalClearAlpha = renderer.getClearAlpha();
var originalAutoClear = renderer.autoClear;
renderer.setRenderTarget( renderTarget );
renderer.autoClear = false;
clearColor = overrideMaterial.clearColor || clearColor;
clearAlpha = overrideMaterial.clearAlpha || clearAlpha;
if ( ( clearColor !== undefined ) && ( clearColor !== null ) ) {
renderer.setClearColor( clearColor );
renderer.setClearAlpha( clearAlpha || 0.0 );
renderer.clear();
}
this.scene.overrideMaterial = overrideMaterial;
renderer.render( this.scene, this.camera );
this.scene.overrideMaterial = null;
// restore original state
renderer.autoClear = originalAutoClear;
renderer.setClearColor( this.originalClearColor );
renderer.setClearAlpha( originalClearAlpha );
},
setSize: function ( width, height ) {
this.width = width;
this.height = height;
this.beautyRenderTarget.setSize( width, height );
this.ssaoRenderTarget.setSize( width, height );
this.normalRenderTarget.setSize( width, height );
this.blurRenderTarget.setSize( width, height );
this.ssaoMaterial.uniforms[ 'resolution' ].value.set( width, height );
this.ssaoMaterial.uniforms[ 'cameraProjectionMatrix' ].value.copy( this.camera.projectionMatrix );
this.ssaoMaterial.uniforms[ 'cameraInverseProjectionMatrix' ].value.getInverse( this.camera.projectionMatrix );
this.blurMaterial.uniforms[ 'resolution' ].value.set( width, height );
},
generateSampleKernel: function () {
var kernelSize = this.kernelSize;
var kernel = this.kernel;
for ( var i = 0; i < kernelSize; i ++ ) {
var sample = new THREE.Vector3();
sample.x = ( Math.random() * 2 ) - 1;
sample.y = ( Math.random() * 2 ) - 1;
sample.z = Math.random();
sample.normalize();
var scale = i / kernelSize;
scale = THREE.MathUtils.lerp( 0.1, 1, scale * scale );
sample.multiplyScalar( scale );
kernel.push( sample );
}
},
generateRandomKernelRotations: function () {
var width = 4, height = 4;
if ( THREE.SimplexNoise === undefined ) {
console.error( 'THREE.SSAOPass: The pass relies on THREE.SimplexNoise.' );
}
var simplex = new THREE.SimplexNoise();
var size = width * height;
var data = new Float32Array( size * 4 );
for ( var i = 0; i < size; i ++ ) {
var stride = i * 4;
var x = ( Math.random() * 2 ) - 1;
var y = ( Math.random() * 2 ) - 1;
var z = 0;
var noise = simplex.noise3d( x, y, z );
data[ stride ] = noise;
data[ stride + 1 ] = noise;
data[ stride + 2 ] = noise;
data[ stride + 3 ] = 1;
}
this.noiseTexture = new THREE.DataTexture( data, width, height, THREE.RGBAFormat, THREE.FloatType );
this.noiseTexture.wrapS = THREE.RepeatWrapping;
this.noiseTexture.wrapT = THREE.RepeatWrapping;
}
} );
THREE.SSAOPass.OUTPUT = {
'Default': 0,
'SSAO': 1,
'Blur': 2,
'Beauty': 3,
'Depth': 4,
'Normal': 5
};