Created
January 28, 2021 08:18
-
-
Save vineeth-pappu/eddd57eb1ae6c50c24ed93930598a9da to your computer and use it in GitHub Desktop.
ThreeJS Edges Geometry Demo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<h1>// Scanning your memories...</h1> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function buildScene() { | |
var scene = new THREE.Scene(); | |
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); | |
var renderer = new THREE.WebGLRenderer(); | |
var composer = new THREE.EffectComposer(renderer); | |
renderer.setSize( window.innerWidth, window.innerHeight ); | |
composer.setSize( window.innerWidth, window.innerHeight ); | |
document.body.appendChild( renderer.domElement ); | |
function onWindowResize() { | |
camera.aspect = window.innerWidth / window.innerHeight; | |
camera.updateProjectionMatrix(); | |
renderer.setSize( window.innerWidth, window.innerHeight ); | |
composer.setSize( window.innerWidth, window.innerHeight ); | |
} | |
window.addEventListener( 'resize', onWindowResize, false ); | |
var cubeGroup = new THREE.Group(); | |
scene.add(cubeGroup); | |
function makeRing(radius, parent) { | |
var geometry = new THREE.CylinderGeometry( radius, radius, 0.1, 64 ); | |
var edges = new THREE.EdgesGeometry( geometry ); | |
var line = new THREE.LineSegments( edges, new THREE.LineBasicMaterial( { color: 0x11ee77 } ) ); | |
parent.add( line ); | |
return line; | |
}; | |
var ring0 = makeRing(3, scene); | |
var ring1 = makeRing(3.3, ring0); | |
var ring2 = makeRing(3.6, ring1); | |
(function() { | |
var geometry = new THREE.OctahedronGeometry( 2, 3 ); | |
var material = new THREE.MeshPhongMaterial( { color: 0x444444, opacity: 0.8, transparent: true } ); | |
var cube = new THREE.Mesh( geometry, material ); | |
cubeGroup.add( cube ); | |
var edges = new THREE.EdgesGeometry( geometry ); | |
var line = new THREE.LineSegments( edges, new THREE.LineBasicMaterial( { color: 0x1188dd } ) ); | |
line.scale.set(1.1, 1.1, 1.1); | |
cubeGroup.add ( line ); | |
})(); | |
var cylinder = (function() { | |
var geometry = new THREE.CylinderGeometry( 8, 8, 1000, 3 ); | |
const edges = new THREE.EdgesGeometry( geometry ); | |
const cylinder = new THREE.LineSegments( edges, new THREE.LineBasicMaterial( { color: 0x444444 } ) ); | |
cylinder.rotation.set(Math.PI/2, 0, 0); | |
scene.add( cylinder ); | |
return cylinder; | |
})(); | |
var light = new THREE.DirectionalLight( 0xFFFFFF, 1 ); | |
scene.add( light ); | |
camera.position.z = 8; | |
var renderScene = new THREE.RenderPass(scene, camera); | |
var glitchPass = new THREE.GlitchPass(); | |
var bloomPass = new THREE.UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 3, 1, 0.4); | |
var copyShader = new THREE.ShaderPass(THREE.CopyShader); | |
copyShader.renderToScreen = true; | |
composer.addPass( renderScene ); | |
composer.addPass( glitchPass ); | |
composer.addPass( bloomPass ); | |
composer.addPass( copyShader ); | |
function render() { | |
cubeGroup.rotation.x += 0.01; | |
cubeGroup.rotation.y += 0.03; | |
ring0.rotation.x += 0.011; | |
ring0.rotation.y += 0.032; | |
ring1.rotation.z += 0.013; | |
ring1.rotation.y += 0.034; | |
ring2.rotation.x += 0.015; | |
ring2.rotation.y += 0.036; | |
cylinder.rotation.y += 0.002; | |
cylinder.rotation.x -= 0.001; | |
cylinder.rotation.z += 0.003; | |
requestAnimationFrame( render ); | |
composer.render(); | |
} | |
render(); | |
} | |
// Everything here down was pulled from ThreeJS Examples under postprocessing and shaders. | |
/** | |
* @author alteredq / http://alteredqualia.com/ | |
* | |
* Full-screen textured quad shader | |
*/ | |
THREE.CopyShader = { | |
uniforms: { | |
"tDiffuse": { value: null }, | |
"opacity": { value: 1.0 } | |
}, | |
vertexShader: [ | |
"varying vec2 vUv;", | |
"void main() {", | |
"vUv = uv;", | |
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", | |
"}" | |
].join( "\n" ), | |
fragmentShader: [ | |
"uniform float opacity;", | |
"uniform sampler2D tDiffuse;", | |
"varying vec2 vUv;", | |
"void main() {", | |
"vec4 texel = texture2D( tDiffuse, vUv );", | |
"gl_FragColor = opacity * texel;", | |
"}" | |
].join( "\n" ) | |
}; | |
/** | |
* @author felixturner / http://airtight.cc/ | |
* | |
* RGB Shift Shader | |
* Shifts red and blue channels from center in opposite directions | |
* Ported from http://kriss.cx/tom/2009/05/rgb-shift/ | |
* by Tom Butterworth / http://kriss.cx/tom/ | |
* | |
* amount: shift distance (1 is width of input) | |
* angle: shift angle in radians | |
*/ | |
THREE.DigitalGlitch = { | |
uniforms: { | |
"tDiffuse": { value: null },//diffuse texture | |
"tDisp": { value: null },//displacement texture for digital glitch squares | |
"byp": { value: 0 },//apply the glitch ? | |
"amount": { value: 0.08 }, | |
"angle": { value: 0.02 }, | |
"seed": { value: 0.02 }, | |
"seed_x": { value: 0.02 },//-1,1 | |
"seed_y": { value: 0.02 },//-1,1 | |
"distortion_x": { value: 0.5 }, | |
"distortion_y": { value: 0.6 }, | |
"col_s": { value: 0.05 } | |
}, | |
vertexShader: [ | |
"varying vec2 vUv;", | |
"void main() {", | |
"vUv = uv;", | |
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", | |
"}" | |
].join( "\n" ), | |
fragmentShader: [ | |
"uniform int byp;",//should we apply the glitch ? | |
"uniform sampler2D tDiffuse;", | |
"uniform sampler2D tDisp;", | |
"uniform float amount;", | |
"uniform float angle;", | |
"uniform float seed;", | |
"uniform float seed_x;", | |
"uniform float seed_y;", | |
"uniform float distortion_x;", | |
"uniform float distortion_y;", | |
"uniform float col_s;", | |
"varying vec2 vUv;", | |
"float rand(vec2 co){", | |
"return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);", | |
"}", | |
"void main() {", | |
"if(byp<1) {", | |
"vec2 p = vUv;", | |
"float xs = floor(gl_FragCoord.x / 0.5);", | |
"float ys = floor(gl_FragCoord.y / 0.5);", | |
//based on staffantans glitch shader for unity https://github.com/staffantan/unityglitch | |
"vec4 normal = texture2D (tDisp, p*seed*seed);", | |
"if(p.y<distortion_x+col_s && p.y>distortion_x-col_s*seed) {", | |
"if(seed_x>0.){", | |
"p.y = 1. - (p.y + distortion_y);", | |
"}", | |
"else {", | |
"p.y = distortion_y;", | |
"}", | |
"}", | |
"if(p.x<distortion_y+col_s && p.x>distortion_y-col_s*seed) {", | |
"if(seed_y>0.){", | |
"p.x=distortion_x;", | |
"}", | |
"else {", | |
"p.x = 1. - (p.x + distortion_x);", | |
"}", | |
"}", | |
"p.x+=normal.x*seed_x*(seed/5.);", | |
"p.y+=normal.y*seed_y*(seed/5.);", | |
//base from RGB shift shader | |
"vec2 offset = amount * vec2( cos(angle), sin(angle));", | |
"vec4 cr = texture2D(tDiffuse, p + offset);", | |
"vec4 cga = texture2D(tDiffuse, p);", | |
"vec4 cb = texture2D(tDiffuse, p - offset);", | |
"gl_FragColor = vec4(cr.r, cga.g, cb.b, cga.a);", | |
//add noise | |
"vec4 snow = 200.*amount*vec4(rand(vec2(xs * seed,ys * seed*50.))*0.2);", | |
"gl_FragColor = gl_FragColor+ snow;", | |
"}", | |
"else {", | |
"gl_FragColor=texture2D (tDiffuse, vUv);", | |
"}", | |
"}" | |
].join( "\n" ) | |
}; | |
/** | |
* @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 ); | |
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 = 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.' ); | |
} | |
} ); | |
/** | |
* @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; | |
} | |
} ); | |
/** | |
* @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 ); | |
} | |
} | |
} ); | |
/** | |
* @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( 10, 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; | |
} | |
} ); | |
/** | |
* @author alteredq / http://alteredqualia.com/ | |
* | |
* Convolution shader | |
* ported from o3d sample to WebGL / GLSL | |
* http://o3d.googlecode.com/svn/trunk/samples/convolution.html | |
*/ | |
THREE.ConvolutionShader = { | |
defines: { | |
"KERNEL_SIZE_FLOAT": "25.0", | |
"KERNEL_SIZE_INT": "25" | |
}, | |
uniforms: { | |
"tDiffuse": { value: null }, | |
"uImageIncrement": { value: new THREE.Vector2( 0.001953125, 0.0 ) }, | |
"cKernel": { value: [] } | |
}, | |
vertexShader: [ | |
"uniform vec2 uImageIncrement;", | |
"varying vec2 vUv;", | |
"void main() {", | |
"vUv = uv - ( ( KERNEL_SIZE_FLOAT - 1.0 ) / 2.0 ) * uImageIncrement;", | |
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", | |
"}" | |
].join( "\n" ), | |
fragmentShader: [ | |
"uniform float cKernel[ KERNEL_SIZE_INT ];", | |
"uniform sampler2D tDiffuse;", | |
"uniform vec2 uImageIncrement;", | |
"varying vec2 vUv;", | |
"void main() {", | |
"vec2 imageCoord = vUv;", | |
"vec4 sum = vec4( 0.0, 0.0, 0.0, 0.0 );", | |
"for( int i = 0; i < KERNEL_SIZE_INT; i ++ ) {", | |
"sum += texture2D( tDiffuse, imageCoord ) * cKernel[ i ];", | |
"imageCoord += uImageIncrement;", | |
"}", | |
"gl_FragColor = sum;", | |
"}" | |
].join( "\n" ), | |
buildKernel: function ( sigma ) { | |
// We lop off the sqrt(2 * pi) * sigma term, since we're going to normalize anyway. | |
function gauss( x, sigma ) { | |
return Math.exp( - ( x * x ) / ( 2.0 * sigma * sigma ) ); | |
} | |
var i, values, sum, halfWidth, kMaxKernelSize = 25, kernelSize = 2 * Math.ceil( sigma * 3.0 ) + 1; | |
if ( kernelSize > kMaxKernelSize ) kernelSize = kMaxKernelSize; | |
halfWidth = ( kernelSize - 1 ) * 0.5; | |
values = new Array( kernelSize ); | |
sum = 0.0; | |
for ( i = 0; i < kernelSize; ++ i ) { | |
values[ i ] = gauss( i - halfWidth, sigma ); | |
sum += values[ i ]; | |
} | |
// normalize the kernel | |
for ( i = 0; i < kernelSize; ++ i ) values[ i ] /= sum; | |
return values; | |
} | |
}; | |
/** | |
* @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.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 ); | |
/** | |
* @author bhouston / http://clara.io/ | |
* | |
* Luminosity | |
* http://en.wikipedia.org/wiki/Luminosity | |
*/ | |
THREE.LuminosityHighPassShader = { | |
shaderID: "luminosityHighPass", | |
uniforms: { | |
"tDiffuse": { type: "t", value: null }, | |
"luminosityThreshold": { type: "f", value: 1.0 }, | |
"smoothWidth": { type: "f", value: 1.0 }, | |
"defaultColor": { type: "c", value: new THREE.Color( 0x000000 ) }, | |
"defaultOpacity": { type: "f", value: 0.0 } | |
}, | |
vertexShader: [ | |
"varying vec2 vUv;", | |
"void main() {", | |
"vUv = uv;", | |
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", | |
"}" | |
].join("\n"), | |
fragmentShader: [ | |
"uniform sampler2D tDiffuse;", | |
"uniform vec3 defaultColor;", | |
"uniform float defaultOpacity;", | |
"uniform float luminosityThreshold;", | |
"uniform float smoothWidth;", | |
"varying vec2 vUv;", | |
"void main() {", | |
"vec4 texel = texture2D( tDiffuse, vUv );", | |
"vec3 luma = vec3( 0.299, 0.587, 0.114 );", | |
"float v = dot( texel.xyz, luma );", | |
"vec4 outputColor = vec4( defaultColor.rgb, defaultOpacity );", | |
"float alpha = smoothstep( luminosityThreshold, luminosityThreshold + smoothWidth, v );", | |
"gl_FragColor = mix( outputColor, texel, alpha );", | |
"}" | |
].join("\n") | |
}; | |
/** | |
* @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.name = "UnrealBloomPass.bright"; | |
this.renderTargetBright.texture.generateMipmaps = false; | |
for( var i=0; i<this.nMips; i++) { | |
var renderTarget = new THREE.WebGLRenderTarget( resx, resy, pars ); | |
renderTarget.texture.name = "UnrealBloomPass.h" + i; | |
renderTarget.texture.generateMipmaps = false; | |
this.renderTargetsHorizontal.push(renderTarget); | |
var renderTarget = new THREE.WebGLRenderTarget( resx, resy, pars ); | |
renderTarget.texture.name = "UnrealBloomPass.v" + i; | |
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 ); | |
buildScene(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/84/three.min.js"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
html, body { | |
padding: 0; | |
margin: 0; | |
width: 100%; | |
height: 100%; | |
overflow: hidden; | |
} | |
h1 { | |
color: white; | |
font-family: VT323; | |
position: absolute; | |
top: 70vh; | |
left: 50vw; | |
font-weight: normal; | |
text-transform: uppercase; | |
letter-spacing: 0.3em; | |
width: 100%; | |
transform: translate(-50%, -50%); | |
font-size: 12px; | |
text-align: center; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<link href="https://fonts.googleapis.com/css?family=VT323" rel="stylesheet" /> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment