webvr js meetup initial commit

This commit is contained in:
Senad Uka
2017-03-11 15:22:17 +01:00
commit 3f640b55db
761 changed files with 264174 additions and 0 deletions

View File

@@ -0,0 +1,319 @@
/**
* @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 },
"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 delta;",
"uniform float tau;",
"void main() {",
"vec4 lastLum = texture2D( lastLum, vUv, MIP_LEVEL_1X1 );",
"vec4 currentLum = texture2D( currentLum, vUv, MIP_LEVEL_1X1 );",
"float fLastLum = lastLum.r;",
"float fCurrentLum = 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 = vec4( vec3( fAdaptedLum ), 1.0 );",
"}"
].join( '\n' )
};
this.materialAdaptiveLum = new THREE.ShaderMaterial( {
uniforms: THREE.UniformsUtils.clone( this.adaptLuminanceShader.uniforms ),
vertexShader: this.adaptLuminanceShader.vertexShader,
fragmentShader: this.adaptLuminanceShader.fragmentShader,
defines: 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.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
this.scene = new THREE.Scene();
this.quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null );
this.quad.frustumCulled = false; // Avoid getting clipped
this.scene.add( this.quad );
};
THREE.AdaptiveToneMappingPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.AdaptiveToneMappingPass,
render: function ( renderer, writeBuffer, readBuffer, delta, 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.quad.material = this.materialLuminance;
this.materialLuminance.uniforms.tDiffuse.value = readBuffer.texture;
renderer.render( this.scene, this.camera, this.currentLuminanceRT );
//Use the new luminance values, the previous luminance and the frame delta to
//adapt the luminance over time.
this.quad.material = this.materialAdaptiveLum;
this.materialAdaptiveLum.uniforms.delta.value = delta;
this.materialAdaptiveLum.uniforms.lastLum.value = this.previousLuminanceRT.texture;
this.materialAdaptiveLum.uniforms.currentLum.value = this.currentLuminanceRT.texture;
renderer.render( this.scene, this.camera, this.luminanceRT );
//Copy the new adapted luminance value so that it can be used by the next frame.
this.quad.material = this.materialCopy;
this.copyUniforms.tDiffuse.value = this.luminanceRT.texture;
renderer.render( this.scene, this.camera, this.previousLuminanceRT );
}
this.quad.material = this.materialToneMap;
this.materialToneMap.uniforms.tDiffuse.value = readBuffer.texture;
renderer.render( this.scene, this.camera, writeBuffer, this.clear );
},
reset: function( renderer ) {
// 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.generateMipmaps = false;
this.previousLuminanceRT = new THREE.WebGLRenderTarget( this.resolution, this.resolution, pars );
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;
this.currentLuminanceRT = new THREE.WebGLRenderTarget( this.resolution, this.resolution, pars );
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.quad.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 );
}
},
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();
}
}
} );

View File

@@ -0,0 +1,117 @@
/**
* @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.renderTargetY = new THREE.WebGLRenderTarget( resolution, resolution, pars );
// 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.PlaneBufferGeometry( 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.render( this.scene, this.camera, this.renderTargetX, true );
// 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.render( this.scene, this.camera, this.renderTargetY, true );
// 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.render( this.scene, this.camera, readBuffer, this.clear );
}
} );
THREE.BloomPass.blurX = new THREE.Vector2( 0.001953125, 0.0 );
THREE.BloomPass.blurY = new THREE.Vector2( 0.0, 0.001953125 );

View File

@@ -0,0 +1,103 @@
/**
* Depth-of-field post-process with bokeh shader
*/
THREE.BokehPass = function ( scene, camera, params ) {
THREE.Pass.call( this );
this.scene = scene;
this.camera = camera;
var focus = ( params.focus !== undefined ) ? params.focus : 1.0;
var aspect = ( params.aspect !== undefined ) ? params.aspect : camera.aspect;
var aperture = ( params.aperture !== undefined ) ? params.aperture : 0.025;
var maxblur = ( params.maxblur !== undefined ) ? params.maxblur : 1.0;
// render targets
var width = params.width || window.innerWidth || 1;
var height = params.height || window.innerHeight || 1;
this.renderTargetColor = new THREE.WebGLRenderTarget( width, height, {
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
format: THREE.RGBFormat
} );
this.renderTargetDepth = this.renderTargetColor.clone();
// depth material
this.materialDepth = new THREE.MeshDepthMaterial();
// bokeh material
if ( THREE.BokehShader === undefined ) {
console.error( "THREE.BokehPass relies on THREE.BokehShader" );
}
var bokehShader = THREE.BokehShader;
var bokehUniforms = THREE.UniformsUtils.clone( bokehShader.uniforms );
bokehUniforms[ "tDepth" ].value = this.renderTargetDepth.texture;
bokehUniforms[ "focus" ].value = focus;
bokehUniforms[ "aspect" ].value = aspect;
bokehUniforms[ "aperture" ].value = aperture;
bokehUniforms[ "maxblur" ].value = maxblur;
this.materialBokeh = new THREE.ShaderMaterial( {
uniforms: bokehUniforms,
vertexShader: bokehShader.vertexShader,
fragmentShader: bokehShader.fragmentShader
} );
this.uniforms = bokehUniforms;
this.needsSwap = false;
this.camera2 = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
this.scene2 = new THREE.Scene();
this.quad2 = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null );
this.quad2.frustumCulled = false; // Avoid getting clipped
this.scene2.add( this.quad2 );
};
THREE.BokehPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.BokehPass,
render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
this.quad2.material = this.materialBokeh;
// Render depth into texture
this.scene.overrideMaterial = this.materialDepth;
renderer.render( this.scene, this.camera, this.renderTargetDepth, true );
// Render bokeh composite
this.uniforms[ "tColor" ].value = readBuffer.texture;
if ( this.renderToScreen ) {
renderer.render( this.scene2, this.camera2 );
} else {
renderer.render( this.scene2, this.camera2, writeBuffer, this.clear );
}
this.scene.overrideMaterial = null;
}
} );

View File

@@ -0,0 +1,44 @@
/**
* @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 );
}
}
} );

View File

@@ -0,0 +1,57 @@
/**
* @author bhouston / http://clara.io/
*/
THREE.CubeTexturePass = function ( camera, envMap, opacity ) {
THREE.Pass.call( this );
this.camera = camera;
this.needsSwap = false;
this.cubeShader = THREE.ShaderLib[ 'cube' ];
this.cubeMesh = new THREE.Mesh(
new THREE.BoxBufferGeometry( 10, 10, 10 ),
new THREE.ShaderMaterial( {
uniforms: this.cubeShader.uniforms,
vertexShader: this.cubeShader.vertexShader,
fragmentShader: this.cubeShader.fragmentShader,
depthTest: false,
depthWrite: false,
side: THREE.BackSide
} )
);
this.envMap = envMap;
this.opacity = ( opacity !== undefined ) ? opacity : 1.0;
this.cubeScene = new THREE.Scene();
this.cubeCamera = new THREE.PerspectiveCamera();
this.cubeScene.add( this.cubeMesh );
};
THREE.CubeTexturePass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.CubeTexturePass,
render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
var oldAutoClear = renderer.autoClear;
renderer.autoClear = false;
this.cubeCamera.projectionMatrix.copy( this.camera.projectionMatrix );
this.cubeCamera.quaternion.setFromRotationMatrix( this.camera.matrixWorld );
this.cubeMesh.material.uniforms[ "tCube" ].value = this.envMap;
this.cubeMesh.material.uniforms[ "opacity" ].value = this.opacity;
this.cubeMesh.material.transparent = ( this.opacity < 1.0 );
renderer.render( this.cubeScene, this.cubeCamera, this.renderToScreen ? null : readBuffer, this.clear );
renderer.autoClear = oldAutoClear;
}
} );

View File

@@ -0,0 +1,60 @@
/**
* @author alteredq / http://alteredqualia.com/
*/
THREE.DotScreenPass = function ( center, angle, scale ) {
THREE.Pass.call( this );
if ( THREE.DotScreenShader === undefined )
console.error( "THREE.DotScreenPass relies on THREE.DotScreenShader" );
var shader = THREE.DotScreenShader;
this.uniforms = THREE.UniformsUtils.clone( shader.uniforms );
if ( center !== undefined ) this.uniforms[ "center" ].value.copy( center );
if ( angle !== undefined ) this.uniforms[ "angle" ].value = angle;
if ( scale !== undefined ) this.uniforms[ "scale" ].value = scale;
this.material = new THREE.ShaderMaterial( {
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.PlaneBufferGeometry( 2, 2 ), null );
this.quad.frustumCulled = false; // Avoid getting clipped
this.scene.add( this.quad );
};
THREE.DotScreenPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.DotScreenPass,
render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
this.uniforms[ "tDiffuse" ].value = readBuffer.texture;
this.uniforms[ "tSize" ].value.set( readBuffer.width, readBuffer.height );
this.quad.material = this.material;
if ( this.renderToScreen ) {
renderer.render( this.scene, this.camera );
} else {
renderer.render( this.scene, this.camera, writeBuffer, this.clear );
}
}
} );

View File

@@ -0,0 +1,175 @@
/**
* @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
};
var size = renderer.getSize();
renderTarget = new THREE.WebGLRenderTarget( size.width, size.height, parameters );
}
this.renderTarget1 = renderTarget;
this.renderTarget2 = renderTarget.clone();
this.writeBuffer = this.renderTarget1;
this.readBuffer = this.renderTarget2;
this.passes = [];
if ( THREE.CopyShader === undefined )
console.error( "THREE.EffectComposer relies on THREE.CopyShader" );
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 = this.renderer.getSize();
pass.setSize( size.width, size.height );
},
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 = this.renderer.getSize();
renderTarget = this.renderTarget1.clone();
renderTarget.setSize( size.width, size.height );
}
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." );
}
} );

View File

@@ -0,0 +1,61 @@
/**
* @author alteredq / http://alteredqualia.com/
*/
THREE.FilmPass = function ( noiseIntensity, scanlinesIntensity, scanlinesCount, grayscale ) {
THREE.Pass.call( this );
if ( THREE.FilmShader === undefined )
console.error( "THREE.FilmPass relies on THREE.FilmShader" );
var shader = THREE.FilmShader;
this.uniforms = THREE.UniformsUtils.clone( shader.uniforms );
this.material = new THREE.ShaderMaterial( {
uniforms: this.uniforms,
vertexShader: shader.vertexShader,
fragmentShader: shader.fragmentShader
} );
if ( grayscale !== undefined ) this.uniforms.grayscale.value = grayscale;
if ( noiseIntensity !== undefined ) this.uniforms.nIntensity.value = noiseIntensity;
if ( scanlinesIntensity !== undefined ) this.uniforms.sIntensity.value = scanlinesIntensity;
if ( scanlinesCount !== undefined ) this.uniforms.sCount.value = scanlinesCount;
this.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
this.scene = new THREE.Scene();
this.quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null );
this.quad.frustumCulled = false; // Avoid getting clipped
this.scene.add( this.quad );
};
THREE.FilmPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.FilmPass,
render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
this.uniforms[ "tDiffuse" ].value = readBuffer.texture;
this.uniforms[ "time" ].value += delta;
this.quad.material = this.material;
if ( this.renderToScreen ) {
renderer.render( this.scene, this.camera );
} else {
renderer.render( this.scene, this.camera, writeBuffer, this.clear );
}
}
} );

View File

@@ -0,0 +1,116 @@
/**
* @author alteredq / http://alteredqualia.com/
*/
THREE.GlitchPass = function ( dt_size ) {
THREE.Pass.call( this );
if ( THREE.DigitalGlitch === undefined ) console.error( "THREE.GlitchPass relies on THREE.DigitalGlitch" );
var shader = THREE.DigitalGlitch;
this.uniforms = THREE.UniformsUtils.clone( shader.uniforms );
if ( dt_size == undefined ) dt_size = 64;
this.uniforms[ "tDisp" ].value = this.generateHeightmap( dt_size );
this.material = new THREE.ShaderMaterial( {
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.PlaneBufferGeometry( 2, 2 ), null );
this.quad.frustumCulled = false; // Avoid getting clipped
this.scene.add( this.quad );
this.goWild = false;
this.curF = 0;
this.generateTrigger();
};
THREE.GlitchPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.GlitchPass,
render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
this.uniforms[ "tDiffuse" ].value = readBuffer.texture;
this.uniforms[ 'seed' ].value = Math.random();//default seeding
this.uniforms[ 'byp' ].value = 0;
if ( this.curF % this.randX == 0 || this.goWild == true ) {
this.uniforms[ 'amount' ].value = Math.random() / 30;
this.uniforms[ 'angle' ].value = THREE.Math.randFloat( - Math.PI, Math.PI );
this.uniforms[ 'seed_x' ].value = THREE.Math.randFloat( - 1, 1 );
this.uniforms[ 'seed_y' ].value = THREE.Math.randFloat( - 1, 1 );
this.uniforms[ 'distortion_x' ].value = THREE.Math.randFloat( 0, 1 );
this.uniforms[ 'distortion_y' ].value = THREE.Math.randFloat( 0, 1 );
this.curF = 0;
this.generateTrigger();
} else if ( this.curF % this.randX < this.randX / 5 ) {
this.uniforms[ 'amount' ].value = Math.random() / 90;
this.uniforms[ 'angle' ].value = THREE.Math.randFloat( - Math.PI, Math.PI );
this.uniforms[ 'distortion_x' ].value = THREE.Math.randFloat( 0, 1 );
this.uniforms[ 'distortion_y' ].value = THREE.Math.randFloat( 0, 1 );
this.uniforms[ 'seed_x' ].value = THREE.Math.randFloat( - 0.3, 0.3 );
this.uniforms[ 'seed_y' ].value = THREE.Math.randFloat( - 0.3, 0.3 );
} else if ( this.goWild == false ) {
this.uniforms[ 'byp' ].value = 1;
}
this.curF ++;
this.quad.material = this.material;
if ( this.renderToScreen ) {
renderer.render( this.scene, this.camera );
} else {
renderer.render( this.scene, this.camera, writeBuffer, this.clear );
}
},
generateTrigger: function() {
this.randX = THREE.Math.randInt( 120, 240 );
},
generateHeightmap: function( dt_size ) {
var data_arr = new Float32Array( dt_size * dt_size * 3 );
var length = dt_size * dt_size;
for ( var i = 0; i < length; i ++ ) {
var val = THREE.Math.randFloat( 0, 1 );
data_arr[ i * 3 + 0 ] = val;
data_arr[ i * 3 + 1 ] = val;
data_arr[ i * 3 + 2 ] = val;
}
var texture = new THREE.DataTexture( data_arr, dt_size, dt_size, THREE.RGBFormat, THREE.FloatType );
texture.needsUpdate = true;
return texture;
}
} );

View File

@@ -0,0 +1,97 @@
/**
* @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.render( this.scene, this.camera, readBuffer, this.clear );
renderer.render( this.scene, this.camera, writeBuffer, this.clear );
// 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 );
}
} );

View File

@@ -0,0 +1,521 @@
/**
* @author spidersharma / http://eduperiment.com/
*/
THREE.OutlinePass = function ( resolution, scene, camera, selectedObjects ) {
this.renderScene = scene;
this.renderCamera = camera;
this.selectedObjects = selectedObjects !== undefined ? selectedObjects : [];
this.visibleEdgeColor = new THREE.Color( 1, 1, 1 );
this.hiddenEdgeColor = new THREE.Color( 0.1, 0.04, 0.02 );
this.edgeGlow = 0.0;
this.usePatternTexture = false;
this.edgeThickness = 1.0;
this.edgeStrength = 3.0;
this.downSampleRatio = 2;
this.pulsePeriod = 0;
THREE.Pass.call( this );
this.resolution = ( resolution !== undefined ) ? new THREE.Vector2( resolution.x, resolution.y ) : new THREE.Vector2( 256, 256 );
var pars = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat };
var resx = Math.round( this.resolution.x / this.downSampleRatio );
var resy = Math.round( this.resolution.y / this.downSampleRatio );
this.maskBufferMaterial = new THREE.MeshBasicMaterial( { color: 0xffffff } );
this.maskBufferMaterial.side = THREE.DoubleSide;
this.renderTargetMaskBuffer = new THREE.WebGLRenderTarget( this.resolution.x, this.resolution.y, pars );
this.renderTargetMaskBuffer.texture.generateMipmaps = false;
this.depthMaterial = new THREE.MeshDepthMaterial();
this.depthMaterial.side = THREE.DoubleSide;
this.depthMaterial.depthPacking = THREE.RGBADepthPacking;
this.depthMaterial.blending = THREE.NoBlending;
this.prepareMaskMaterial = this.getPrepareMaskMaterial();
this.prepareMaskMaterial.side = THREE.DoubleSide;
this.renderTargetDepthBuffer = new THREE.WebGLRenderTarget( this.resolution.x, this.resolution.y, pars );
this.renderTargetDepthBuffer.texture.generateMipmaps = false;
this.renderTargetMaskDownSampleBuffer = new THREE.WebGLRenderTarget( resx, resy, pars );
this.renderTargetMaskDownSampleBuffer.texture.generateMipmaps = false;
this.renderTargetBlurBuffer1 = new THREE.WebGLRenderTarget( resx, resy, pars );
this.renderTargetBlurBuffer1.texture.generateMipmaps = false;
this.renderTargetBlurBuffer2 = new THREE.WebGLRenderTarget( Math.round( resx / 2 ), Math.round( resy / 2 ), pars );
this.renderTargetBlurBuffer2.texture.generateMipmaps = false;
this.edgeDetectionMaterial = this.getEdgeDetectionMaterial();
this.renderTargetEdgeBuffer1 = new THREE.WebGLRenderTarget( resx, resy, pars );
this.renderTargetEdgeBuffer1.texture.generateMipmaps = false;
this.renderTargetEdgeBuffer2 = new THREE.WebGLRenderTarget( Math.round( resx / 2 ), Math.round( resy / 2 ), pars );
this.renderTargetEdgeBuffer2.texture.generateMipmaps = false;
var MAX_EDGE_THICKNESS = 4;
var MAX_EDGE_GLOW = 4;
this.separableBlurMaterial1 = this.getSeperableBlurMaterial( MAX_EDGE_THICKNESS );
this.separableBlurMaterial1.uniforms[ "texSize" ].value = new THREE.Vector2( resx, resy );
this.separableBlurMaterial1.uniforms[ "kernelRadius" ].value = 1;
this.separableBlurMaterial2 = this.getSeperableBlurMaterial( MAX_EDGE_GLOW );
this.separableBlurMaterial2.uniforms[ "texSize" ].value = new THREE.Vector2( Math.round( resx / 2 ), Math.round( resy / 2 ) );
this.separableBlurMaterial2.uniforms[ "kernelRadius" ].value = MAX_EDGE_GLOW;
// Overlay material
this.overlayMaterial = this.getOverlayMaterial();
// copy material
if ( THREE.CopyShader === undefined )
console.error( "THREE.OutlinePass 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.NoBlending,
depthTest: false,
depthWrite: false,
transparent: true
} );
this.enabled = true;
this.needsSwap = false;
this.oldClearColor = new THREE.Color();
this.oldClearAlpha = 1;
this.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
this.scene = new THREE.Scene();
this.quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null );
this.quad.frustumCulled = false; // Avoid getting clipped
this.scene.add( this.quad );
this.tempPulseColor1 = new THREE.Color();
this.tempPulseColor2 = new THREE.Color();
this.textureMatrix = new THREE.Matrix4();
};
THREE.OutlinePass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.OutlinePass,
dispose: function () {
this.renderTargetMaskBuffer.dispose();
this.renderTargetDepthBuffer.dispose();
this.renderTargetMaskDownSampleBuffer.dispose();
this.renderTargetBlurBuffer1.dispose();
this.renderTargetBlurBuffer2.dispose();
this.renderTargetEdgeBuffer1.dispose();
this.renderTargetEdgeBuffer2.dispose();
},
setSize: function ( width, height ) {
this.renderTargetMaskBuffer.setSize( width, height );
var resx = Math.round( width / this.downSampleRatio );
var resy = Math.round( height / this.downSampleRatio );
this.renderTargetMaskDownSampleBuffer.setSize( resx, resy );
this.renderTargetBlurBuffer1.setSize( resx, resy );
this.renderTargetEdgeBuffer1.setSize( resx, resy );
this.separableBlurMaterial1.uniforms[ "texSize" ].value = new THREE.Vector2( resx, resy );
resx = Math.round( resx / 2 );
resy = Math.round( resy / 2 );
this.renderTargetBlurBuffer2.setSize( resx, resy );
this.renderTargetEdgeBuffer2.setSize( resx, resy );
this.separableBlurMaterial2.uniforms[ "texSize" ].value = new THREE.Vector2( resx, resy );
},
changeVisibilityOfSelectedObjects: function ( bVisible ) {
function gatherSelectedMeshesCallBack( object ) {
if ( object instanceof THREE.Mesh ) object.visible = bVisible;
}
for ( var i = 0; i < this.selectedObjects.length; i ++ ) {
var selectedObject = this.selectedObjects[ i ];
selectedObject.traverse( gatherSelectedMeshesCallBack );
}
},
changeVisibilityOfNonSelectedObjects: function ( bVisible ) {
var selectedMeshes = [];
function gatherSelectedMeshesCallBack( object ) {
if ( object instanceof THREE.Mesh ) selectedMeshes.push( object );
}
for ( var i = 0; i < this.selectedObjects.length; i ++ ) {
var selectedObject = this.selectedObjects[ i ];
selectedObject.traverse( gatherSelectedMeshesCallBack );
}
function VisibilityChangeCallBack( object ) {
if ( object instanceof THREE.Mesh ) {
var bFound = false;
for ( var i = 0; i < selectedMeshes.length; i ++ ) {
var selectedObjectId = selectedMeshes[ i ].id;
if ( selectedObjectId === object.id ) {
bFound = true;
break;
}
}
if ( ! bFound ) {
var visibility = object.visible;
if ( ! bVisible || object.bVisible ) object.visible = bVisible;
object.bVisible = visibility;
}
}
}
this.renderScene.traverse( VisibilityChangeCallBack );
},
updateTextureMatrix: function () {
this.textureMatrix.set( 0.5, 0.0, 0.0, 0.5,
0.0, 0.5, 0.0, 0.5,
0.0, 0.0, 0.5, 0.5,
0.0, 0.0, 0.0, 1.0 );
this.textureMatrix.multiply( this.renderCamera.projectionMatrix );
this.textureMatrix.multiply( this.renderCamera.matrixWorldInverse );
},
render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
if ( this.selectedObjects.length === 0 ) return;
this.oldClearColor.copy( renderer.getClearColor() );
this.oldClearAlpha = renderer.getClearAlpha();
var oldAutoClear = renderer.autoClear;
renderer.autoClear = false;
if ( maskActive ) renderer.context.disable( renderer.context.STENCIL_TEST );
renderer.setClearColor( 0xffffff, 1 );
// Make selected objects invisible
this.changeVisibilityOfSelectedObjects( false );
// 1. Draw Non Selected objects in the depth buffer
this.renderScene.overrideMaterial = this.depthMaterial;
renderer.render( this.renderScene, this.renderCamera, this.renderTargetDepthBuffer, true );
// Make selected objects visible
this.changeVisibilityOfSelectedObjects( true );
// Update Texture Matrix for Depth compare
this.updateTextureMatrix();
// Make non selected objects invisible, and draw only the selected objects, by comparing the depth buffer of non selected objects
this.changeVisibilityOfNonSelectedObjects( false );
this.renderScene.overrideMaterial = this.prepareMaskMaterial;
this.prepareMaskMaterial.uniforms[ "cameraNearFar" ].value = new THREE.Vector2( this.renderCamera.near, this.renderCamera.far );
this.prepareMaskMaterial.uniforms[ "depthTexture" ].value = this.renderTargetDepthBuffer.texture;
this.prepareMaskMaterial.uniforms[ "textureMatrix" ].value = this.textureMatrix;
renderer.render( this.renderScene, this.renderCamera, this.renderTargetMaskBuffer, true );
this.renderScene.overrideMaterial = null;
this.changeVisibilityOfNonSelectedObjects( true );
// 2. Downsample to Half resolution
this.quad.material = this.materialCopy;
this.copyUniforms[ "tDiffuse" ].value = this.renderTargetMaskBuffer.texture;
renderer.render( this.scene, this.camera, this.renderTargetMaskDownSampleBuffer, true );
this.tempPulseColor1.copy( this.visibleEdgeColor );
this.tempPulseColor2.copy( this.hiddenEdgeColor );
if ( this.pulsePeriod > 0 ) {
var scalar = ( 1 + 0.25 ) / 2 + Math.cos( performance.now() * 0.01 / this.pulsePeriod ) * ( 1.0 - 0.25 ) / 2;
this.tempPulseColor1.multiplyScalar( scalar );
this.tempPulseColor2.multiplyScalar( scalar );
}
// 3. Apply Edge Detection Pass
this.quad.material = this.edgeDetectionMaterial;
this.edgeDetectionMaterial.uniforms[ "maskTexture" ].value = this.renderTargetMaskDownSampleBuffer.texture;
this.edgeDetectionMaterial.uniforms[ "texSize" ].value = new THREE.Vector2( this.renderTargetMaskDownSampleBuffer.width, this.renderTargetMaskDownSampleBuffer.height );
this.edgeDetectionMaterial.uniforms[ "visibleEdgeColor" ].value = this.tempPulseColor1;
this.edgeDetectionMaterial.uniforms[ "hiddenEdgeColor" ].value = this.tempPulseColor2;
renderer.render( this.scene, this.camera, this.renderTargetEdgeBuffer1, true );
// 4. Apply Blur on Half res
this.quad.material = this.separableBlurMaterial1;
this.separableBlurMaterial1.uniforms[ "colorTexture" ].value = this.renderTargetEdgeBuffer1.texture;
this.separableBlurMaterial1.uniforms[ "direction" ].value = THREE.OutlinePass.BlurDirectionX;
this.separableBlurMaterial1.uniforms[ "kernelRadius" ].value = this.edgeThickness;
renderer.render( this.scene, this.camera, this.renderTargetBlurBuffer1, true );
this.separableBlurMaterial1.uniforms[ "colorTexture" ].value = this.renderTargetBlurBuffer1.texture;
this.separableBlurMaterial1.uniforms[ "direction" ].value = THREE.OutlinePass.BlurDirectionY;
renderer.render( this.scene, this.camera, this.renderTargetEdgeBuffer1, true );
// Apply Blur on quarter res
this.quad.material = this.separableBlurMaterial2;
this.separableBlurMaterial2.uniforms[ "colorTexture" ].value = this.renderTargetEdgeBuffer1.texture;
this.separableBlurMaterial2.uniforms[ "direction" ].value = THREE.OutlinePass.BlurDirectionX;
renderer.render( this.scene, this.camera, this.renderTargetBlurBuffer2, true );
this.separableBlurMaterial2.uniforms[ "colorTexture" ].value = this.renderTargetBlurBuffer2.texture;
this.separableBlurMaterial2.uniforms[ "direction" ].value = THREE.OutlinePass.BlurDirectionY;
renderer.render( this.scene, this.camera, this.renderTargetEdgeBuffer2, true );
// Blend it additively over the input texture
this.quad.material = this.overlayMaterial;
this.overlayMaterial.uniforms[ "maskTexture" ].value = this.renderTargetMaskBuffer.texture;
this.overlayMaterial.uniforms[ "edgeTexture1" ].value = this.renderTargetEdgeBuffer1.texture;
this.overlayMaterial.uniforms[ "edgeTexture2" ].value = this.renderTargetEdgeBuffer2.texture;
this.overlayMaterial.uniforms[ "patternTexture" ].value = this.patternTexture;
this.overlayMaterial.uniforms[ "edgeStrength" ].value = this.edgeStrength;
this.overlayMaterial.uniforms[ "edgeGlow" ].value = this.edgeGlow;
this.overlayMaterial.uniforms[ "usePatternTexture" ].value = this.usePatternTexture;
if ( maskActive ) renderer.context.enable( renderer.context.STENCIL_TEST );
renderer.render( this.scene, this.camera, readBuffer, false );
renderer.setClearColor( this.oldClearColor, this.oldClearAlpha );
renderer.autoClear = oldAutoClear;
},
getPrepareMaskMaterial: function () {
return new THREE.ShaderMaterial( {
uniforms: {
"depthTexture": { value: null },
"cameraNearFar": { value: new THREE.Vector2( 0.5, 0.5 ) },
"textureMatrix": { value: new THREE.Matrix4() }
},
vertexShader:
"varying vec2 vUv;\
varying vec4 projTexCoord;\
varying vec4 vPosition;\
uniform mat4 textureMatrix;\
void main() {\
vUv = uv;\
vPosition = modelViewMatrix * vec4( position, 1.0 );\
vec4 worldPosition = modelMatrix * vec4( position, 1.0 );\
projTexCoord = textureMatrix * worldPosition;\
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\
}",
fragmentShader:
"#include <packing>\
varying vec2 vUv;\
varying vec4 vPosition;\
varying vec4 projTexCoord;\
uniform sampler2D depthTexture;\
uniform vec2 cameraNearFar;\
\
void main() {\
float depth = unpackRGBAToDepth(texture2DProj( depthTexture, projTexCoord ));\
float viewZ = -perspectiveDepthToViewZ( depth, cameraNearFar.x, cameraNearFar.y );\
float depthTest = (-vPosition.z > viewZ) ? 1.0 : 0.0;\
gl_FragColor = vec4(0.0, depthTest, 1.0, 1.0);\
}"
} );
},
getEdgeDetectionMaterial: function () {
return new THREE.ShaderMaterial( {
uniforms: {
"maskTexture": { value: null },
"texSize": { value: new THREE.Vector2( 0.5, 0.5 ) },
"visibleEdgeColor": { value: new THREE.Vector3( 1.0, 1.0, 1.0 ) },
"hiddenEdgeColor": { value: new THREE.Vector3( 1.0, 1.0, 1.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 maskTexture;\
uniform vec2 texSize;\
uniform vec3 visibleEdgeColor;\
uniform vec3 hiddenEdgeColor;\
\
void main() {\n\
vec2 invSize = 1.0 / texSize;\
vec4 uvOffset = vec4(1.0, 0.0, 0.0, 1.0) * vec4(invSize, invSize);\
vec4 c1 = texture2D( maskTexture, vUv + uvOffset.xy);\
vec4 c2 = texture2D( maskTexture, vUv - uvOffset.xy);\
vec4 c3 = texture2D( maskTexture, vUv + uvOffset.yw);\
vec4 c4 = texture2D( maskTexture, vUv - uvOffset.yw);\
float diff1 = (c1.r - c2.r)*0.5;\
float diff2 = (c3.r - c4.r)*0.5;\
float d = length( vec2(diff1, diff2) );\
float a1 = min(c1.g, c2.g);\
float a2 = min(c3.g, c4.g);\
float visibilityFactor = min(a1, a2);\
vec3 edgeColor = 1.0 - visibilityFactor > 0.001 ? visibleEdgeColor : hiddenEdgeColor;\
gl_FragColor = vec4(edgeColor, 1.0) * vec4(d);\
}"
} );
},
getSeperableBlurMaterial: function ( maxRadius ) {
return new THREE.ShaderMaterial( {
defines: {
"MAX_RADIUS": maxRadius,
},
uniforms: {
"colorTexture": { value: null },
"texSize": { value: new THREE.Vector2( 0.5, 0.5 ) },
"direction": { value: new THREE.Vector2( 0.5, 0.5 ) },
"kernelRadius": { value: 1.0 }
},
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;\
uniform sampler2D colorTexture;\
uniform vec2 texSize;\
uniform vec2 direction;\
uniform float kernelRadius;\
\
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 weightSum = gaussianPdf(0.0, kernelRadius);\
vec3 diffuseSum = texture2D( colorTexture, vUv).rgb * weightSum;\
vec2 delta = direction * invSize * kernelRadius/float(MAX_RADIUS);\
vec2 uvOffset = delta;\
for( int i = 1; i <= MAX_RADIUS; i ++ ) {\
float w = gaussianPdf(uvOffset.x, kernelRadius);\
vec3 sample1 = texture2D( colorTexture, vUv + uvOffset).rgb;\
vec3 sample2 = texture2D( colorTexture, vUv - uvOffset).rgb;\
diffuseSum += ((sample1 + sample2) * w);\
weightSum += (2.0 * w);\
uvOffset += delta;\
}\
gl_FragColor = vec4(diffuseSum/weightSum, 1.0);\
}"
} );
},
getOverlayMaterial: function () {
return new THREE.ShaderMaterial( {
uniforms: {
"maskTexture": { value: null },
"edgeTexture1": { value: null },
"edgeTexture2": { value: null },
"patternTexture": { value: null },
"edgeStrength": { value: 1.0 },
"edgeGlow": { value: 1.0 },
"usePatternTexture": { 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 maskTexture;\
uniform sampler2D edgeTexture1;\
uniform sampler2D edgeTexture2;\
uniform sampler2D patternTexture;\
uniform float edgeStrength;\
uniform float edgeGlow;\
uniform bool usePatternTexture;\
\
void main() {\
vec4 edgeValue1 = texture2D(edgeTexture1, vUv);\
vec4 edgeValue2 = texture2D(edgeTexture2, vUv);\
vec4 maskColor = texture2D(maskTexture, vUv);\
vec4 patternColor = texture2D(patternTexture, 6.0 * vUv);\
float visibilityFactor = 1.0 - maskColor.g > 0.0 ? 1.0 : 0.5;\
vec4 edgeValue = edgeValue1 + edgeValue2 * edgeGlow;\
vec4 finalColor = edgeStrength * maskColor.r * edgeValue;\
if(usePatternTexture)\
finalColor += + visibilityFactor * (1.0 - maskColor.r) * (1.0 - patternColor.r);\
gl_FragColor = finalColor;\
}",
blending: THREE.AdditiveBlending,
depthTest: false,
depthWrite: false,
transparent: true
} );
}
} );
THREE.OutlinePass.BlurDirectionX = new THREE.Vector2( 1.0, 0.0 );
THREE.OutlinePass.BlurDirectionY = new THREE.Vector2( 0.0, 1.0 );

View File

@@ -0,0 +1,63 @@
/**
* @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.render( this.scene, this.camera, this.renderToScreen ? null : readBuffer, this.clear );
if ( this.clearColor ) {
renderer.setClearColor( oldClearColor, oldClearAlpha );
}
this.scene.overrideMaterial = null;
renderer.autoClear = oldAutoClear;
}
} );

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,169 @@
/**
*
* Supersample Anti-Aliasing Render Pass
*
* @author bhouston / http://clara.io/
*
* This manual approach to SSAA re-renders the scene ones for each sample with camera jitter and accumulates the results.
*
* References: https://en.wikipedia.org/wiki/Supersampling
*
*/
THREE.SSAARenderPass = function ( scene, camera, clearColor, clearAlpha ) {
THREE.Pass.call( this );
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;
if ( THREE.CopyShader === undefined ) console.error( "THREE.SSAARenderPass relies on THREE.CopyShader" );
var copyShader = THREE.CopyShader;
this.copyUniforms = THREE.UniformsUtils.clone( copyShader.uniforms );
this.copyMaterial = new THREE.ShaderMaterial( {
uniforms: this.copyUniforms,
vertexShader: copyShader.vertexShader,
fragmentShader: copyShader.fragmentShader,
premultipliedAlpha: true,
transparent: true,
blending: THREE.AdditiveBlending,
depthTest: false,
depthWrite: false
} );
this.camera2 = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
this.scene2 = new THREE.Scene();
this.quad2 = new THREE.Mesh( new THREE.PlaneGeometry( 2, 2 ), this.copyMaterial );
this.quad2.frustumCulled = false; // Avoid getting clipped
this.scene2.add( this.quad2 );
};
THREE.SSAARenderPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.SSAARenderPass,
dispose: function() {
if ( this.sampleRenderTarget ) {
this.sampleRenderTarget.dispose();
this.sampleRenderTarget = null;
}
},
setSize: function ( width, height ) {
if ( this.sampleRenderTarget ) this.sampleRenderTarget.setSize( width, height );
},
render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
if ( ! this.sampleRenderTarget ) {
this.sampleRenderTarget = new THREE.WebGLRenderTarget( readBuffer.width, readBuffer.height,
{ minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat } );
}
var jitterOffsets = THREE.SSAARenderPass.JitterVectors[ Math.max( 0, Math.min( this.sampleLevel, 5 ) ) ];
var autoClear = renderer.autoClear;
renderer.autoClear = false;
var oldClearColor = renderer.getClearColor().getHex();
var oldClearAlpha = renderer.getClearAlpha();
var baseSampleWeight = 1.0 / jitterOffsets.length;
var roundingRange = 1 / 32;
this.copyUniforms[ "tDiffuse" ].value = this.sampleRenderTarget.texture;
var width = readBuffer.width, height = readBuffer.height;
// render the scene multiple times, each slightly jitter offset from the last and accumulate the results.
for ( var i = 0; i < jitterOffsets.length; i ++ ) {
var 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 );
}
var 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 );
sampleWeight += roundingRange * uniformCenteredDistribution;
}
this.copyUniforms[ "opacity" ].value = sampleWeight;
renderer.setClearColor( this.clearColor, this.clearAlpha );
renderer.render( this.scene, this.camera, this.sampleRenderTarget, true );
if (i === 0) {
renderer.setClearColor( 0x000000, 0.0 );
}
renderer.render( this.scene2, this.camera2, this.renderToScreen ? null : writeBuffer, (i === 0) );
}
if ( this.camera.clearViewOffset ) this.camera.clearViewOffset();
renderer.autoClear = autoClear;
renderer.setClearColor( 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
THREE.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 ]
]
];

View File

@@ -0,0 +1,64 @@
/**
* @author alteredq / http://alteredqualia.com/
*/
THREE.SavePass = function ( renderTarget ) {
THREE.Pass.call( this );
if ( THREE.CopyShader === undefined )
console.error( "THREE.SavePass relies on THREE.CopyShader" );
var shader = THREE.CopyShader;
this.textureID = "tDiffuse";
this.uniforms = THREE.UniformsUtils.clone( shader.uniforms );
this.material = new THREE.ShaderMaterial( {
uniforms: this.uniforms,
vertexShader: shader.vertexShader,
fragmentShader: shader.fragmentShader
} );
this.renderTarget = renderTarget;
if ( this.renderTarget === undefined ) {
this.renderTargetParameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: false };
this.renderTarget = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, this.renderTargetParameters );
}
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.PlaneBufferGeometry( 2, 2 ), null );
this.quad.frustumCulled = false; // Avoid getting clipped
this.scene.add( this.quad );
};
THREE.SavePass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.SavePass,
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.render( this.scene, this.camera, this.renderTarget, this.clear );
}
} );

View File

@@ -0,0 +1,67 @@
/**
* @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: 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.PlaneBufferGeometry( 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;
if ( this.renderToScreen ) {
renderer.render( this.scene, this.camera );
} else {
renderer.render( this.scene, this.camera, writeBuffer, this.clear );
}
}
} );

View File

@@ -0,0 +1,119 @@
/**
*
* Temporal Anti-Aliasing Render Pass
*
* @author bhouston / http://clara.io/
*
* When there is no motion in the scene, the TAA render pass accumulates jittered camera samples across frames to create a high quality anti-aliased result.
*
* References:
*
* TODO: Add support for motion vector pas so that accumulation of samples across frames can occur on dynamics scenes.
*
*/
THREE.TAARenderPass = function ( scene, camera, params ) {
if ( THREE.SSAARenderPass === undefined ) {
console.error( "THREE.TAARenderPass relies on THREE.SSAARenderPass" );
}
THREE.SSAARenderPass.call( this, scene, camera, params );
this.sampleLevel = 0;
this.accumulate = false;
};
THREE.TAARenderPass.JitterVectors = THREE.SSAARenderPass.JitterVectors;
THREE.TAARenderPass.prototype = Object.assign( Object.create( THREE.SSAARenderPass.prototype ), {
constructor: THREE.TAARenderPass,
render: function ( renderer, writeBuffer, readBuffer, delta ) {
if( ! this.accumulate ) {
THREE.SSAARenderPass.prototype.render.call( this, renderer, writeBuffer, readBuffer, delta );
this.accumulateIndex = -1;
return;
}
var jitterOffsets = THREE.TAARenderPass.JitterVectors[ 5 ];
if ( ! this.sampleRenderTarget ) {
this.sampleRenderTarget = new THREE.WebGLRenderTarget( readBuffer.width, readBuffer.height, this.params );
}
if ( ! this.holdRenderTarget ) {
this.holdRenderTarget = new THREE.WebGLRenderTarget( readBuffer.width, readBuffer.height, this.params );
}
if( this.accumulate && this.accumulateIndex === -1 ) {
THREE.SSAARenderPass.prototype.render.call( this, renderer, this.holdRenderTarget, readBuffer, delta );
this.accumulateIndex = 0;
}
var autoClear = renderer.autoClear;
renderer.autoClear = false;
var 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 );
for ( var i = 0; i < numSamplesPerFrame; i ++ ) {
var j = this.accumulateIndex;
var jitterOffset = jitterOffsets[j];
if ( this.camera.setViewOffset ) {
this.camera.setViewOffset( readBuffer.width, readBuffer.height,
jitterOffset[ 0 ] * 0.0625, jitterOffset[ 1 ] * 0.0625, // 0.0625 = 1 / 16
readBuffer.width, readBuffer.height );
}
renderer.render( this.scene, this.camera, writeBuffer, true );
renderer.render( this.scene2, this.camera2, this.sampleRenderTarget, ( this.accumulateIndex === 0 ) );
this.accumulateIndex ++;
if( this.accumulateIndex >= jitterOffsets.length ) break;
}
if ( this.camera.clearViewOffset ) this.camera.clearViewOffset();
}
var accumulationWeight = this.accumulateIndex * sampleWeight;
if( accumulationWeight > 0 ) {
this.copyUniforms[ "opacity" ].value = 1.0;
this.copyUniforms[ "tDiffuse" ].value = this.sampleRenderTarget.texture;
renderer.render( this.scene2, this.camera2, writeBuffer, true );
}
if( accumulationWeight < 1.0 ) {
this.copyUniforms[ "opacity" ].value = 1.0 - accumulationWeight;
this.copyUniforms[ "tDiffuse" ].value = this.holdRenderTarget.texture;
renderer.render( this.scene2, this.camera2, writeBuffer, ( accumulationWeight === 0 ) );
}
renderer.autoClear = autoClear;
}
});

View File

@@ -0,0 +1,60 @@
/**
* @author alteredq / http://alteredqualia.com/
*/
THREE.TexturePass = function ( map, opacity ) {
THREE.Pass.call( this );
if ( THREE.CopyShader === undefined )
console.error( "THREE.TexturePass relies on THREE.CopyShader" );
var shader = THREE.CopyShader;
this.map = map;
this.opacity = ( opacity !== undefined ) ? opacity : 1.0;
this.uniforms = THREE.UniformsUtils.clone( shader.uniforms );
this.material = new THREE.ShaderMaterial( {
uniforms: this.uniforms,
vertexShader: shader.vertexShader,
fragmentShader: shader.fragmentShader,
depthTest: false,
depthWrite: false
} );
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.PlaneBufferGeometry( 2, 2 ), null );
this.quad.frustumCulled = false; // Avoid getting clipped
this.scene.add( this.quad );
};
THREE.TexturePass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.TexturePass,
render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
var oldAutoClear = renderer.autoClear;
renderer.autoClear = false;
this.quad.material = this.material;
this.uniforms[ "opacity" ].value = this.opacity;
this.uniforms[ "tDiffuse" ].value = this.map;
this.material.transparent = ( this.opacity < 1.0 );
renderer.render( this.scene, this.camera, this.renderToScreen ? null : readBuffer, this.clear );
renderer.autoClear = oldAutoClear;
}
} );

View File

@@ -0,0 +1,333 @@
/**
* @author spidersharma / http://eduperiment.com/
Inspired from Unreal Engine::
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);
// 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.generateMipmaps = false;
for( var i=0; i<this.nMips; i++) {
var renderTarget = new THREE.WebGLRenderTarget( resx, resy, pars );
renderTarget.texture.generateMipmaps = false;
this.renderTargetsHorizontal.push(renderTarget);
var renderTarget = new THREE.WebGLRenderTarget( resx, resy, pars );
renderTarget.texture.generateMipmaps = false;
this.renderTargetsVertical.push(renderTarget);
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.BloomPass 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.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
this.scene = new THREE.Scene();
this.quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null );
this.quad.frustumCulled = false; // Avoid getting clipped
this.scene.add( this.quad );
};
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, delta, maskActive ) {
this.oldClearColor.copy( renderer.getClearColor() );
this.oldClearAlpha = renderer.getClearAlpha();
var oldAutoClear = renderer.autoClear;
renderer.autoClear = false;
renderer.setClearColor( new THREE.Color( 0, 0, 0 ), 0 );
if ( maskActive ) renderer.context.disable( renderer.context.STENCIL_TEST );
// 1. Extract Bright Areas
this.highPassUniforms[ "tDiffuse" ].value = readBuffer.texture;
this.highPassUniforms[ "luminosityThreshold" ].value = this.threshold;
this.quad.material = this.materialHighPassFilter;
renderer.render( this.scene, this.camera, this.renderTargetBright, true );
// 2. Blur All the mips progressively
var inputRenderTarget = this.renderTargetBright;
for(var i=0; i<this.nMips; i++) {
this.quad.material = this.separableBlurMaterials[i];
this.separableBlurMaterials[i].uniforms[ "colorTexture" ].value = inputRenderTarget.texture;
this.separableBlurMaterials[i].uniforms[ "direction" ].value = THREE.UnrealBloomPass.BlurDirectionX;
renderer.render( this.scene, this.camera, this.renderTargetsHorizontal[i], true );
this.separableBlurMaterials[i].uniforms[ "colorTexture" ].value = this.renderTargetsHorizontal[i].texture;
this.separableBlurMaterials[i].uniforms[ "direction" ].value = THREE.UnrealBloomPass.BlurDirectionY;
renderer.render( this.scene, this.camera, this.renderTargetsVertical[i], true );
inputRenderTarget = this.renderTargetsVertical[i];
}
// Composite All the mips
this.quad.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.render( this.scene, this.camera, this.renderTargetsHorizontal[0], true );
// Blend it additively over the input texture
this.quad.material = this.materialCopy;
this.copyUniforms[ "tDiffuse" ].value = this.renderTargetsHorizontal[0].texture;
if ( maskActive ) renderer.context.enable( renderer.context.STENCIL_TEST );
renderer.render( this.scene, this.camera, readBuffer, false );
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 );