UNPKG

playcanvas

Version:

PlayCanvas WebGL game engine

181 lines (162 loc) 8.54 kB
// --------------- POST EFFECT DEFINITION --------------- // /** * @class * @name BokehEffect * @classdesc Implements the BokehEffect post processing effect. * @description Creates new instance of the post effect. * @augments PostEffect * @param {GraphicsDevice} graphicsDevice - The graphics device of the application. * @property {number} maxBlur The maximum amount of blurring. Ranges from 0 to 1. * @property {number} aperture Bigger values create a shallower depth of field. * @property {number} focus Controls the focus of the effect. */ function BokehEffect(graphicsDevice) { pc.PostEffect.call(this, graphicsDevice); this.needsDepthBuffer = true; // Shader 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 fshader = [ pc.ShaderChunks.get(graphicsDevice, pc.SHADERLANGUAGE_GLSL).get('screenDepthPS'), '', 'varying vec2 vUv0;', '', 'uniform sampler2D uColorBuffer;', '', 'uniform float uMaxBlur;', // max blur amount 'uniform float uAperture;', // uAperture - bigger values for shallower depth of field '', 'uniform float uFocus;', 'uniform float uAspect;', '', 'void main()', '{', ' vec2 aspectCorrect = vec2( 1.0, uAspect );', '', ' float factor = ((getLinearScreenDepth(vUv0) * -1.0) - uFocus) / camera_params.y;', '', ' vec2 dofblur = vec2 ( clamp( factor * uAperture, -uMaxBlur, uMaxBlur ) );', '', ' vec2 dofblur9 = dofblur * 0.9;', ' vec2 dofblur7 = dofblur * 0.7;', ' vec2 dofblur4 = dofblur * 0.4;', '', ' vec4 col;', '', ' col = texture2D( uColorBuffer, vUv0 );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( 0.0, 0.4 ) * aspectCorrect ) * dofblur );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( 0.15, 0.37 ) * aspectCorrect ) * dofblur );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( 0.29, 0.29 ) * aspectCorrect ) * dofblur );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( -0.37, 0.15 ) * aspectCorrect ) * dofblur );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( 0.40, 0.0 ) * aspectCorrect ) * dofblur );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( 0.37, -0.15 ) * aspectCorrect ) * dofblur );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( 0.29, -0.29 ) * aspectCorrect ) * dofblur );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( -0.15, -0.37 ) * aspectCorrect ) * dofblur );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( 0.0, -0.4 ) * aspectCorrect ) * dofblur );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( -0.15, 0.37 ) * aspectCorrect ) * dofblur );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( -0.29, 0.29 ) * aspectCorrect ) * dofblur );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( 0.37, 0.15 ) * aspectCorrect ) * dofblur );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( -0.4, 0.0 ) * aspectCorrect ) * dofblur );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( -0.37, -0.15 ) * aspectCorrect ) * dofblur );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( -0.29, -0.29 ) * aspectCorrect ) * dofblur );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( 0.15, -0.37 ) * aspectCorrect ) * dofblur );', '', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( 0.15, 0.37 ) * aspectCorrect ) * dofblur9 );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( -0.37, 0.15 ) * aspectCorrect ) * dofblur9 );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( 0.37, -0.15 ) * aspectCorrect ) * dofblur9 );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( -0.15, -0.37 ) * aspectCorrect ) * dofblur9 );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( -0.15, 0.37 ) * aspectCorrect ) * dofblur9 );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( 0.37, 0.15 ) * aspectCorrect ) * dofblur9 );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( -0.37, -0.15 ) * aspectCorrect ) * dofblur9 );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( 0.15, -0.37 ) * aspectCorrect ) * dofblur9 );', '', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( 0.29, 0.29 ) * aspectCorrect ) * dofblur7 );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( 0.40, 0.0 ) * aspectCorrect ) * dofblur7 );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( 0.29, -0.29 ) * aspectCorrect ) * dofblur7 );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( 0.0, -0.4 ) * aspectCorrect ) * dofblur7 );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( -0.29, 0.29 ) * aspectCorrect ) * dofblur7 );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( -0.4, 0.0 ) * aspectCorrect ) * dofblur7 );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( -0.29, -0.29 ) * aspectCorrect ) * dofblur7 );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( 0.0, 0.4 ) * aspectCorrect ) * dofblur7 );', '', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( 0.29, 0.29 ) * aspectCorrect ) * dofblur4 );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( 0.4, 0.0 ) * aspectCorrect ) * dofblur4 );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( 0.29, -0.29 ) * aspectCorrect ) * dofblur4 );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( 0.0, -0.4 ) * aspectCorrect ) * dofblur4 );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( -0.29, 0.29 ) * aspectCorrect ) * dofblur4 );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( -0.4, 0.0 ) * aspectCorrect ) * dofblur4 );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( -0.29, -0.29 ) * aspectCorrect ) * dofblur4 );', ' col += texture2D( uColorBuffer, vUv0 + ( vec2( 0.0, 0.4 ) * aspectCorrect ) * dofblur4 );', '', ' gl_FragColor = col / 41.0;', ' gl_FragColor.a = 1.0;', '}' ].join('\n'); this.shader = pc.ShaderUtils.createShader(graphicsDevice, { uniqueName: 'BokehShader', attributes: { aPosition: pc.SEMANTIC_POSITION }, vertexGLSL: pc.PostEffect.quadVertexShader, fragmentGLSL: fshader }); // Uniforms this.maxBlur = 0.02; this.aperture = 1; this.focus = 1; } BokehEffect.prototype = Object.create(pc.PostEffect.prototype); BokehEffect.prototype.constructor = BokehEffect; Object.assign(BokehEffect.prototype, { render: function (inputTarget, outputTarget, rect) { var device = this.device; var scope = device.scope; scope.resolve('uMaxBlur').setValue(this.maxBlur); scope.resolve('uAperture').setValue(this.aperture); scope.resolve('uFocus').setValue(this.focus); scope.resolve('uAspect').setValue(device.width / device.height); scope.resolve('uColorBuffer').setValue(inputTarget.colorBuffer); this.drawQuad(outputTarget, this.shader, rect); } }); // ----------------- SCRIPT DEFINITION ------------------ // var Bokeh = pc.createScript('bokeh'); Bokeh.attributes.add('maxBlur', { type: 'number', default: 0.02, min: 0, max: 1, title: 'Max Blur' }); Bokeh.attributes.add('aperture', { type: 'number', default: 1, min: 0, max: 1, title: 'Aperture' }); Bokeh.attributes.add('focus', { type: 'number', default: 1, title: 'Focus' }); Bokeh.prototype.initialize = function () { this.effect = new BokehEffect(this.app.graphicsDevice); this.effect.maxBlur = this.maxBlur; this.effect.aperture = this.aperture; this.effect.focus = this.focus; this.on('attr', function (name, value) { this.effect[name] = value; }, this); var queue = this.entity.camera.postEffects; queue.addEffect(this.effect); this.on('state', function (enabled) { if (enabled) { queue.addEffect(this.effect); } else { queue.removeEffect(this.effect); } }); this.on('destroy', function () { queue.removeEffect(this.effect); }); };