Initial depth-of-field progress

master
Robin Hawkes 2016-03-11 11:38:08 +00:00
rodzic 2b63ca9ff7
commit b77f8c9496
16 zmienionych plików z 1504 dodań i 137 usunięć

915
dist/vizicities.js vendored

Plik diff jest za duży Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -8,6 +8,9 @@ import DOMRenderer3D from './DOMRenderer3D';
import DOMRenderer2D from './DOMRenderer2D';
import Camera from './Camera';
import Picking from './Picking';
import EffectComposer from '../vendor/EffectComposer';
import RenderPass from '../vendor/RenderPass';
import BokehPass from '../vendor/BokehPass';
class Engine extends EventEmitter {
constructor(container, world) {
@ -33,12 +36,35 @@ class Engine extends EventEmitter {
this.clock = new THREE.Clock();
this._frustum = new THREE.Frustum();
this._initPostProcessing();
}
// TODO: Set up composer to automatically resize on viewport change
_initPostProcessing() {
var renderPass = new RenderPass(this._scene, this._camera);
var bokehPass = new BokehPass(this._scene, this._camera, {
focus: 1,
aperture: 0.6,
// maxblur: 1.0,
width: this._renderer.getSize().width,
height: this._renderer.getSize().height
});
bokehPass.renderToScreen = true;
this._composer = new EffectComposer(this._renderer);
this._composer.addPass(renderPass);
this._composer.addPass(bokehPass);
}
update(delta) {
this.emit('preRender');
this._renderer.render(this._scene, this._camera);
// this._renderer.render(this._scene, this._camera);
this._composer.render();
// Render picking scene
// this._renderer.render(this._picking._pickingScene, this._camera);

Wyświetl plik

@ -55,7 +55,7 @@ class Skybox {
_initSkybox() {
// Cube camera for skybox
this._cubeCamera = new THREE.CubeCamera(1, 2000000, 128);
this._cubeCamera = new THREE.CubeCamera(1, 200000, 128);
// Cube material
var cubeTarget = this._cubeCamera.renderTarget;

110
src/vendor/BokehPass.js vendored 100644
Wyświetl plik

@ -0,0 +1,110 @@
// jscs:disable
/* eslint-disable */
import THREE from 'three';
import BokehShader from './BokehShader';
/**
* Depth-of-field post-process with bokeh shader
*/
var BokehPass = function ( scene, camera, params ) {
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 ( BokehShader === undefined ) {
console.error( "THREE.BokehPass relies on THREE.BokehShader" );
}
var bokehShader = BokehShader;
var bokehUniforms = THREE.UniformsUtils.clone( bokehShader.uniforms );
bokehUniforms[ "tDepth" ].value = this.renderTargetDepth;
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.enabled = true;
this.needsSwap = false;
this.renderToScreen = false;
this.clear = 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.scene2.add( this.quad2 );
};
BokehPass.prototype = {
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;
if ( this.renderToScreen ) {
renderer.render( this.scene2, this.camera2 );
} else {
renderer.render( this.scene2, this.camera2, writeBuffer, this.clear );
}
this.scene.overrideMaterial = null;
}
};
export default BokehPass;
THREE.BokehPass = BokehPass;

124
src/vendor/BokehShader.js vendored 100644
Wyświetl plik

@ -0,0 +1,124 @@
// jscs:disable
/* eslint-disable */
import THREE from 'three';
/**
* @author alteredq / http://alteredqualia.com/
*
* Depth-of-field shader with bokeh
* ported from GLSL shader by Martins Upitis
* http://artmartinsh.blogspot.com/2010/02/glsl-lens-blur-filter-with-bokeh.html
*/
var BokehShader = {
uniforms: {
"tColor": { type: "t", value: null },
"tDepth": { type: "t", value: null },
"focus": { type: "f", value: 1.0 },
"aspect": { type: "f", value: 1.0 },
"aperture": { type: "f", value: 0.025 },
"maxblur": { type: "f", 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 tColor;",
"uniform sampler2D tDepth;",
"uniform float maxblur;", // max blur amount
"uniform float aperture;", // aperture - bigger values for shallower depth of field
"uniform float focus;",
"uniform float aspect;",
"void main() {",
"vec2 aspectcorrect = vec2( 1.0, aspect );",
"vec4 depth1 = texture2D( tDepth, vUv );",
"float factor = depth1.x - focus;",
"vec2 dofblur = vec2 ( clamp( factor * aperture, -maxblur, maxblur ) );",
"vec2 dofblur9 = dofblur * 0.9;",
"vec2 dofblur7 = dofblur * 0.7;",
"vec2 dofblur4 = dofblur * 0.4;",
"vec4 col = vec4( 0.0 );",
"col += texture2D( tColor, vUv.xy );",
"col += texture2D( tColor, vUv.xy + ( vec2( 0.0, 0.4 ) * aspectcorrect ) * dofblur );",
"col += texture2D( tColor, vUv.xy + ( vec2( 0.15, 0.37 ) * aspectcorrect ) * dofblur );",
"col += texture2D( tColor, vUv.xy + ( vec2( 0.29, 0.29 ) * aspectcorrect ) * dofblur );",
"col += texture2D( tColor, vUv.xy + ( vec2( -0.37, 0.15 ) * aspectcorrect ) * dofblur );",
"col += texture2D( tColor, vUv.xy + ( vec2( 0.40, 0.0 ) * aspectcorrect ) * dofblur );",
"col += texture2D( tColor, vUv.xy + ( vec2( 0.37, -0.15 ) * aspectcorrect ) * dofblur );",
"col += texture2D( tColor, vUv.xy + ( vec2( 0.29, -0.29 ) * aspectcorrect ) * dofblur );",
"col += texture2D( tColor, vUv.xy + ( vec2( -0.15, -0.37 ) * aspectcorrect ) * dofblur );",
"col += texture2D( tColor, vUv.xy + ( vec2( 0.0, -0.4 ) * aspectcorrect ) * dofblur );",
"col += texture2D( tColor, vUv.xy + ( vec2( -0.15, 0.37 ) * aspectcorrect ) * dofblur );",
"col += texture2D( tColor, vUv.xy + ( vec2( -0.29, 0.29 ) * aspectcorrect ) * dofblur );",
"col += texture2D( tColor, vUv.xy + ( vec2( 0.37, 0.15 ) * aspectcorrect ) * dofblur );",
"col += texture2D( tColor, vUv.xy + ( vec2( -0.4, 0.0 ) * aspectcorrect ) * dofblur );",
"col += texture2D( tColor, vUv.xy + ( vec2( -0.37, -0.15 ) * aspectcorrect ) * dofblur );",
"col += texture2D( tColor, vUv.xy + ( vec2( -0.29, -0.29 ) * aspectcorrect ) * dofblur );",
"col += texture2D( tColor, vUv.xy + ( vec2( 0.15, -0.37 ) * aspectcorrect ) * dofblur );",
"col += texture2D( tColor, vUv.xy + ( vec2( 0.15, 0.37 ) * aspectcorrect ) * dofblur9 );",
"col += texture2D( tColor, vUv.xy + ( vec2( -0.37, 0.15 ) * aspectcorrect ) * dofblur9 );",
"col += texture2D( tColor, vUv.xy + ( vec2( 0.37, -0.15 ) * aspectcorrect ) * dofblur9 );",
"col += texture2D( tColor, vUv.xy + ( vec2( -0.15, -0.37 ) * aspectcorrect ) * dofblur9 );",
"col += texture2D( tColor, vUv.xy + ( vec2( -0.15, 0.37 ) * aspectcorrect ) * dofblur9 );",
"col += texture2D( tColor, vUv.xy + ( vec2( 0.37, 0.15 ) * aspectcorrect ) * dofblur9 );",
"col += texture2D( tColor, vUv.xy + ( vec2( -0.37, -0.15 ) * aspectcorrect ) * dofblur9 );",
"col += texture2D( tColor, vUv.xy + ( vec2( 0.15, -0.37 ) * aspectcorrect ) * dofblur9 );",
"col += texture2D( tColor, vUv.xy + ( vec2( 0.29, 0.29 ) * aspectcorrect ) * dofblur7 );",
"col += texture2D( tColor, vUv.xy + ( vec2( 0.40, 0.0 ) * aspectcorrect ) * dofblur7 );",
"col += texture2D( tColor, vUv.xy + ( vec2( 0.29, -0.29 ) * aspectcorrect ) * dofblur7 );",
"col += texture2D( tColor, vUv.xy + ( vec2( 0.0, -0.4 ) * aspectcorrect ) * dofblur7 );",
"col += texture2D( tColor, vUv.xy + ( vec2( -0.29, 0.29 ) * aspectcorrect ) * dofblur7 );",
"col += texture2D( tColor, vUv.xy + ( vec2( -0.4, 0.0 ) * aspectcorrect ) * dofblur7 );",
"col += texture2D( tColor, vUv.xy + ( vec2( -0.29, -0.29 ) * aspectcorrect ) * dofblur7 );",
"col += texture2D( tColor, vUv.xy + ( vec2( 0.0, 0.4 ) * aspectcorrect ) * dofblur7 );",
"col += texture2D( tColor, vUv.xy + ( vec2( 0.29, 0.29 ) * aspectcorrect ) * dofblur4 );",
"col += texture2D( tColor, vUv.xy + ( vec2( 0.4, 0.0 ) * aspectcorrect ) * dofblur4 );",
"col += texture2D( tColor, vUv.xy + ( vec2( 0.29, -0.29 ) * aspectcorrect ) * dofblur4 );",
"col += texture2D( tColor, vUv.xy + ( vec2( 0.0, -0.4 ) * aspectcorrect ) * dofblur4 );",
"col += texture2D( tColor, vUv.xy + ( vec2( -0.29, 0.29 ) * aspectcorrect ) * dofblur4 );",
"col += texture2D( tColor, vUv.xy + ( vec2( -0.4, 0.0 ) * aspectcorrect ) * dofblur4 );",
"col += texture2D( tColor, vUv.xy + ( vec2( -0.29, -0.29 ) * aspectcorrect ) * dofblur4 );",
"col += texture2D( tColor, vUv.xy + ( vec2( 0.0, 0.4 ) * aspectcorrect ) * dofblur4 );",
"gl_FragColor = col / 41.0;",
"gl_FragColor.a = 1.0;",
"}"
].join( "\n" )
};
export default BokehShader;
THREE.BokehShader = BokehShader;

Wyświetl plik

@ -1,5 +1,5 @@
// jscs:disable
/*eslint eqeqeq:0*/
/* eslint-disable */
import THREE from 'three';

Wyświetl plik

@ -1,5 +1,5 @@
// jscs:disable
/*eslint eqeqeq:0*/
/* eslint-disable */
/**
* @author mrdoob / http://mrdoob.com/

Wyświetl plik

@ -1,5 +1,5 @@
// jscs:disable
/*eslint eqeqeq:0*/
/* eslint-disable */
/**
* Based on http://www.emagix.net/academic/mscs-project/item/camera-sync-with-css3-and-webgl-threejs

54
src/vendor/CopyShader.js vendored 100644
Wyświetl plik

@ -0,0 +1,54 @@
// jscs:disable
/* eslint-disable */
import THREE from 'three';
/**
* @author alteredq / http://alteredqualia.com/
*
* Full-screen textured quad shader
*/
var CopyShader = {
uniforms: {
"tDiffuse": { type: "t", value: null },
"opacity": { type: "f", 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" )
};
export default CopyShader;
THREE.CopyShader = CopyShader;

150
src/vendor/EffectComposer.js vendored 100644
Wyświetl plik

@ -0,0 +1,150 @@
// jscs:disable
/* eslint-disable */
import THREE from 'three';
import CopyShader from './CopyShader';
import ShaderPass from './ShaderPass';
import MaskPass, {ClearMaskPass} from './MaskPass';
/**
* @author alteredq / http://alteredqualia.com/
*/
var EffectComposer = function ( renderer, renderTarget ) {
this.renderer = renderer;
if ( renderTarget === undefined ) {
var pixelRatio = renderer.getPixelRatio();
var width = Math.floor( renderer.context.canvas.width / pixelRatio ) || 1;
var height = Math.floor( renderer.context.canvas.height / pixelRatio ) || 1;
var parameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat, stencilBuffer: false };
renderTarget = new THREE.WebGLRenderTarget( width, height, parameters );
}
this.renderTarget1 = renderTarget;
this.renderTarget2 = renderTarget.clone();
this.writeBuffer = this.renderTarget1;
this.readBuffer = this.renderTarget2;
this.passes = [];
if ( CopyShader === undefined )
console.error( "EffectComposer relies on THREE.CopyShader" );
this.copyPass = new ShaderPass( CopyShader );
};
EffectComposer.prototype = {
swapBuffers: function() {
var tmp = this.readBuffer;
this.readBuffer = this.writeBuffer;
this.writeBuffer = tmp;
},
addPass: function ( pass ) {
this.passes.push( pass );
},
insertPass: function ( pass, index ) {
this.passes.splice( index, 0, pass );
},
render: function ( delta ) {
this.writeBuffer = this.renderTarget1;
this.readBuffer = this.renderTarget2;
var maskActive = false;
var pass, i, il = this.passes.length;
for ( i = 0; i < il; i ++ ) {
pass = this.passes[ i ];
if ( ! pass.enabled ) 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 ( pass instanceof MaskPass ) {
maskActive = true;
} else if ( pass instanceof ClearMaskPass ) {
maskActive = false;
}
}
},
reset: function ( renderTarget ) {
if ( renderTarget === undefined ) {
renderTarget = this.renderTarget1.clone();
var pixelRatio = this.renderer.getPixelRatio();
renderTarget.setSize(
Math.floor( this.renderer.context.canvas.width / pixelRatio ),
Math.floor( this.renderer.context.canvas.height / pixelRatio )
);
}
this.renderTarget1.dispose();
this.renderTarget1 = renderTarget;
this.renderTarget2.dispose();
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 );
}
};
export default EffectComposer;
THREE.EffectComposer = EffectComposer;

97
src/vendor/MaskPass.js vendored 100644
Wyświetl plik

@ -0,0 +1,97 @@
// jscs:disable
/* eslint-disable */
import THREE from 'three';
/**
* @author alteredq / http://alteredqualia.com/
*/
var MaskPass = function ( scene, camera ) {
this.scene = scene;
this.camera = camera;
this.enabled = true;
this.clear = true;
this.needsSwap = false;
this.inverse = false;
};
MaskPass.prototype = {
render: function ( renderer, writeBuffer, readBuffer, delta ) {
var context = renderer.context;
// don't update color or depth
context.colorMask( false, false, false, false );
context.depthMask( false );
// set up stencil
var writeValue, clearValue;
if ( this.inverse ) {
writeValue = 0;
clearValue = 1;
} else {
writeValue = 1;
clearValue = 0;
}
context.enable( context.STENCIL_TEST );
context.stencilOp( context.REPLACE, context.REPLACE, context.REPLACE );
context.stencilFunc( context.ALWAYS, writeValue, 0xffffffff );
context.clearStencil( clearValue );
// draw into the stencil buffer
renderer.render( this.scene, this.camera, readBuffer, this.clear );
renderer.render( this.scene, this.camera, writeBuffer, this.clear );
// re-enable update of color and depth
context.colorMask( true, true, true, true );
context.depthMask( true );
// only render where stencil is set to 1
context.stencilFunc( context.EQUAL, 1, 0xffffffff ); // draw if == 1
context.stencilOp( context.KEEP, context.KEEP, context.KEEP );
}
};
var ClearMaskPass = function () {
this.enabled = true;
};
ClearMaskPass.prototype = {
render: function ( renderer, writeBuffer, readBuffer, delta ) {
var context = renderer.context;
context.disable( context.STENCIL_TEST );
}
};
export default MaskPass;
export {ClearMaskPass as ClearMaskPass};
THREE.MaskPass = MaskPass;
THREE.ClearMaskPass = ClearMaskPass;

Wyświetl plik

@ -1,5 +1,5 @@
// jscs:disable
/*eslint eqeqeq:0*/
/* eslint-disable */
import THREE from 'three';
import Hammer from 'hammerjs';

59
src/vendor/RenderPass.js vendored 100644
Wyświetl plik

@ -0,0 +1,59 @@
// jscs:disable
/* eslint-disable */
import THREE from 'three';
/**
* @author alteredq / http://alteredqualia.com/
*/
var RenderPass = function ( scene, camera, overrideMaterial, clearColor, clearAlpha ) {
this.scene = scene;
this.camera = camera;
this.overrideMaterial = overrideMaterial;
this.clearColor = clearColor;
this.clearAlpha = ( clearAlpha !== undefined ) ? clearAlpha : 1;
this.oldClearColor = new THREE.Color();
this.oldClearAlpha = 1;
this.enabled = true;
this.clear = true;
this.needsSwap = false;
};
RenderPass.prototype = {
render: function ( renderer, writeBuffer, readBuffer, delta ) {
this.scene.overrideMaterial = this.overrideMaterial;
if ( this.clearColor ) {
this.oldClearColor.copy( renderer.getClearColor() );
this.oldClearAlpha = renderer.getClearAlpha();
renderer.setClearColor( this.clearColor, this.clearAlpha );
}
renderer.render( this.scene, this.camera, readBuffer, this.clear );
if ( this.clearColor ) {
renderer.setClearColor( this.oldClearColor, this.oldClearAlpha );
}
this.scene.overrideMaterial = null;
}
};
export default RenderPass;
THREE.RenderPass = RenderPass;

78
src/vendor/ShaderPass.js vendored 100644
Wyświetl plik

@ -0,0 +1,78 @@
// jscs:disable
/* eslint-disable */
import THREE from 'three';
/**
* @author alteredq / http://alteredqualia.com/
*/
var ShaderPass = function( shader, textureID ) {
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.renderToScreen = false;
this.enabled = true;
this.needsSwap = true;
this.clear = 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.scene.add( this.quad );
};
ShaderPass.prototype = {
render: function( renderer, writeBuffer, readBuffer, delta ) {
if ( this.uniforms[ this.textureID ] ) {
this.uniforms[ this.textureID ].value = readBuffer;
}
this.quad.material = this.material;
if ( this.renderToScreen ) {
renderer.render( this.scene, this.camera );
} else {
renderer.render( this.scene, this.camera, writeBuffer, this.clear );
}
}
};
export default ShaderPass;
THREE.ShaderPass = ShaderPass;