├── demo.png ├── demo ├── phaser2.png ├── 8710000952_a7830143dd_b.jpg ├── 14001968572_cf2d689031_b.jpg ├── index.html └── demo.js ├── README.md └── src ├── Vignette.js ├── SNoise.js └── FilmGrain.js /demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jounii/phaser-filterkit/HEAD/demo.png -------------------------------------------------------------------------------- /demo/phaser2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jounii/phaser-filterkit/HEAD/demo/phaser2.png -------------------------------------------------------------------------------- /demo/8710000952_a7830143dd_b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jounii/phaser-filterkit/HEAD/demo/8710000952_a7830143dd_b.jpg -------------------------------------------------------------------------------- /demo/14001968572_cf2d689031_b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jounii/phaser-filterkit/HEAD/demo/14001968572_cf2d689031_b.jpg -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Filter Test 6 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | -------------------------------------------------------------------------------- /demo/demo.js: -------------------------------------------------------------------------------- 1 | var background; 2 | var filter = []; 3 | var FILTER_VIGNETTE = 0; 4 | var FILTER_FILMGRAIN = 1; 5 | var FILTER_SNOISE = 2; 6 | var game = new Phaser.Game(800, 600, Phaser.AUTO, 'filter-example', { preload: preload, create: create, update: update }); 7 | 8 | function preload() { 9 | 10 | game.load.image('phaser', 'phaser2.png'); 11 | game.load.image('background', '8710000952_a7830143dd_b.jpg'); 12 | game.load.script('filter-vignette', '../src/Vignette.js'); 13 | //game.load.script('filter-snoise', '../src/SNoise.js'); 14 | game.load.script('filter-filmgrain', '../src/FilmGrain.js'); 15 | 16 | } 17 | 18 | function create() { 19 | 20 | background = game.add.sprite(0, 0, 'background'); 21 | background.width = 800; 22 | background.height = 600; 23 | 24 | filter[FILTER_VIGNETTE] = game.add.filter('Vignette'); 25 | filter[FILTER_VIGNETTE].size = 0.3; 26 | filter[FILTER_VIGNETTE].amount = 0.5; 27 | filter[FILTER_VIGNETTE].alpha = 1.0; 28 | 29 | //filter[FILTER_SNOISE] = game.add.filter('SNoise'); 30 | 31 | filter[FILTER_FILMGRAIN] = game.add.filter('FilmGrain'); 32 | filter[FILTER_FILMGRAIN].color = 0.6; 33 | filter[FILTER_FILMGRAIN].amount = 0.04; 34 | filter[FILTER_FILMGRAIN].luminance = 0.8; 35 | 36 | //background.filters = [filter[FILTER_FILMGRAIN], filter[FILTER_VIGNETTE]]; 37 | game.stage.filters = [filter[FILTER_FILMGRAIN], filter[FILTER_VIGNETTE]]; 38 | 39 | var logo = game.add.sprite(game.world.centerX, game.world.centerY, 'phaser'); 40 | logo.anchor.setTo(0.5, 0.5); 41 | 42 | } 43 | 44 | var direction = -1; 45 | 46 | function update() { 47 | var f = filter[FILTER_FILMGRAIN]; 48 | /* 49 | f.amount += 0.01 * direction; 50 | if (f.amount <= 0) { 51 | f.amount = 0; 52 | direction = 1; 53 | } else if (f.amount >= 1.0) { 54 | f.amount = 1.0; 55 | direction = -1; 56 | } 57 | */ 58 | 59 | f.update(); 60 | 61 | } 62 | 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | phaser-filterkit 2 | ================ 3 | 4 | Assorted kit of PhaserJS WebGL Filters. 5 | 6 | Filters 7 | ======= 8 | 9 | Vignette 10 | -------- 11 | 12 | Original shader by Evan Wallace. 13 | 14 | http://evanw.github.io/glfx.js/ 15 | https://github.com/evanw/glfx.js/blob/master/src/filters/adjust/vignette.js 16 | 17 | FilmGrain 18 | --------- 19 | 20 | Original shader by Martins Upitis. 21 | 22 | http://devlog-martinsh.blogspot.fi/2013/05/image-imperfections-and-film-grain-post.html 23 | 24 | Notes: The shader parameters were published and the texture randomness had some issues 25 | with Phaser time uniform (seconds) over time. Shader modified so that it basically loops 26 | every 120 seconds and the texture rotation is randomized to certain angle range. 27 | 28 | SNoise 29 | ------ 30 | 31 | Original shader by Ian McEwan, Ashima Arts. 32 | 33 | https://github.com/ashima/webgl-noise 34 | 35 | Not sure if this is useful. Possibly with some tweaks and parameterization 36 | could make it more useful. But use this as base for other filters. 37 | 38 | 39 | License 40 | ======= 41 | 42 | As code is mostly based on existing shaders so their licensing carries over: 43 | 44 | ------- 45 | This work is licensed under a Creative Commons Attribution 3.0 Unported License. 46 | So you are free to share, modify and adapt it for your needs, and even use it for commercial use. 47 | I would also love to hear about a project you are using it. 48 | 49 | ------- 50 | Permission is hereby granted, free of charge, to any person obtaining a copy 51 | of this software and associated documentation files (the "Software"), to deal 52 | in the Software without restriction, including without limitation the rights 53 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 54 | copies of the Software, and to permit persons to whom the Software is 55 | furnished to do so, subject to the following conditions: 56 | 57 | The above copyright notice and this permission notice shall be included in 58 | all copies or substantial portions of the Software. 59 | 60 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 61 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 62 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 63 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 64 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 65 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 66 | THE SOFTWARE. -------------------------------------------------------------------------------- /src/Vignette.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @filter Vignette 4 | * @description Adds a simulated lens edge darkening effect. 5 | * 6 | * param size 0 to 1 (0 for center of frame, 1 for edge of frame) 7 | * param amount 0 to 1 (0 for no effect, 1 for maximum lens darkening) 8 | * 9 | * Original shader by Evan Wallace. 10 | * 11 | * http://evanw.github.io/glfx.js/ 12 | * 13 | * https://github.com/evanw/glfx.js/blob/master/src/filters/adjust/vignette.js 14 | * 15 | * Converted to Phaser/PIXI by Jouni Airaksinen, jouni.airaksinen@sc5.io 16 | * 17 | */ 18 | Phaser.Filter.Vignette = function (game) { 19 | 20 | Phaser.Filter.call(this, game); 21 | 22 | this.uniforms.alpha = { type: '1f', value: 1.0 }; 23 | this.uniforms.size = { type: '1f', value: 0.5 }; 24 | this.uniforms.amount = { type: '1f', value: 0.5 }; 25 | 26 | this.fragmentSrc = [ 27 | 28 | "precision mediump float;", 29 | "uniform sampler2D uSampler;", 30 | "uniform float time;", 31 | "uniform float alpha;", 32 | "uniform float size;", 33 | "uniform float amount;", 34 | "varying vec2 vTextureCoord;", 35 | 36 | "void main(void) {", 37 | 38 | "vec4 color = texture2D(uSampler, vTextureCoord);", 39 | 40 | "float dist = distance(vTextureCoord, vec2(0.5, 0.5));", 41 | 42 | "color.rgb *= smoothstep(0.8, size * 1.0 * 0.799, dist * (alpha * amount + size));", 43 | "gl_FragColor = color;", 44 | "}" 45 | ]; 46 | 47 | }; 48 | 49 | Phaser.Filter.Vignette.prototype = Object.create(Phaser.Filter.prototype); 50 | Phaser.Filter.Vignette.prototype.constructor = Phaser.Filter.Vignette; 51 | 52 | Object.defineProperty(Phaser.Filter.Vignette.prototype, 'alpha', { 53 | 54 | get: function() { 55 | return this.uniforms.alpha.value; 56 | }, 57 | 58 | set: function(value) { 59 | this.uniforms.alpha.value = value; 60 | } 61 | 62 | }); 63 | 64 | Object.defineProperty(Phaser.Filter.Vignette.prototype, 'size', { 65 | 66 | get: function() { 67 | return this.uniforms.size.value; 68 | }, 69 | 70 | set: function(value) { 71 | this.uniforms.size.value = Math.max(0, Math.min(value, 1)); 72 | } 73 | 74 | }); 75 | 76 | Object.defineProperty(Phaser.Filter.Vignette.prototype, 'amount', { 77 | 78 | get: function() { 79 | return this.uniforms.amount.value; 80 | }, 81 | 82 | set: function(value) { 83 | this.uniforms.amount.value = Math.max(0, Math.min(value, 1)); 84 | } 85 | 86 | }); -------------------------------------------------------------------------------- /src/SNoise.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @filter SNoise 4 | * 5 | * Original shader by Ian McEwan, Ashima Arts. 6 | * 7 | * https://github.com/ashima/webgl-noise 8 | * 9 | * Converted to Phaser/PIXI by Jouni Airaksinen, jouni.airaksinen@sc5.io 10 | * 11 | * Notes: Not sure if this is useful. Possibly with some tweaks and parameterization 12 | * could make it more useful. But use this as base for other filters. 13 | * 14 | */ 15 | 16 | // 17 | // Description : Array and textureless GLSL 2D simplex noise function. 18 | // Author : Ian McEwan, Ashima Arts. 19 | // Maintainer : ijm 20 | // Lastmod : 20110822 (ijm) 21 | // License : Copyright (C) 2011 Ashima Arts. All rights reserved. 22 | // Distributed under the MIT License. See LICENSE file. 23 | // https://github.com/ashima/webgl-noise 24 | // 25 | 26 | Phaser.Filter.SNoise = function (game) { 27 | 28 | Phaser.Filter.call(this, game); 29 | 30 | this.uniforms.amount = { type: '1f', value: 0.5 }; 31 | this.uniforms.z = { type: '1f', value: 0.0 }; 32 | 33 | this.fragmentSrc = [ 34 | "precision mediump float;", 35 | "uniform float time;", 36 | "uniform float uz;", 37 | "uniform float amount;", 38 | "uniform sampler2D uSampler;", 39 | "varying vec2 vTextureCoord;", 40 | 41 | "vec3 mod289(vec3 x) {", 42 | "return x - floor(x * (1.0 / 289.0)) * 289.0;", 43 | "}", 44 | 45 | "vec2 mod289(vec2 x) {", 46 | "return x - floor(x * (1.0 / 289.0)) * 289.0;", 47 | "}", 48 | 49 | "vec4 mod289(vec4 x) {", 50 | "return x - floor(x * (1.0 / 289.0)) * 289.0;", 51 | "}", 52 | 53 | "vec4 permute(vec4 x) {", 54 | "return mod289(((x*34.0)+1.0)*x);", 55 | "}", 56 | 57 | "vec4 taylorInvSqrt(vec4 r) {", 58 | "return 1.79284291400159 - 0.85373472095314 * r;", 59 | "}", 60 | 61 | "float snoise(vec3 v) {", 62 | "const vec2 C = vec2(1.0/6.0, 1.0/3.0);", 63 | "const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);", 64 | 65 | // First corner 66 | "vec3 i = floor(v + dot(v, C.yyy) );", 67 | "vec3 x0 = v - i + dot(i, C.xxx) ;", 68 | 69 | // Other corners 70 | "vec3 g = step(x0.yzx, x0.xyz);", 71 | "vec3 l = 1.0 - g;", 72 | "vec3 i1 = min( g.xyz, l.zxy );", 73 | "vec3 i2 = max( g.xyz, l.zxy );", 74 | 75 | // x0 = x0 - 0.0 + 0.0 * C.xxx; 76 | // x1 = x0 - i1 + 1.0 * C.xxx; 77 | // x2 = x0 - i2 + 2.0 * C.xxx; 78 | // x3 = x0 - 1.0 + 3.0 * C.xxx; 79 | "vec3 x1 = x0 - i1 + C.xxx;", 80 | "vec3 x2 = x0 - i2 + C.yyy;", // 2.0*C.x = 1/3 = C.y 81 | "vec3 x3 = x0 - D.yyy;", // -1.0+3.0*C.x = -0.5 = -D.y 82 | 83 | // Permutations 84 | "i = mod289(i);", 85 | "vec4 p = permute( permute( permute(", 86 | " i.z + vec4(0.0, i1.z, i2.z, 1.0 ))", 87 | "+ i.y + vec4(0.0, i1.y, i2.y, 1.0 ))", 88 | "+ i.x + vec4(0.0, i1.x, i2.x, 1.0 ));", 89 | 90 | // Gradients: 7x7 points over a square, mapped onto an octahedron. 91 | // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) 92 | "float n_ = 0.142857142857;", // 1.0/7.0 93 | "vec3 ns = n_ * D.wyz - D.xzx;", 94 | 95 | "vec4 j = p - 49.0 * floor(p * ns.z * ns.z);", // mod(p,7*7) 96 | 97 | "vec4 x_ = floor(j * ns.z);", 98 | "vec4 y_ = floor(j - 7.0 * x_ );", // mod(j,N) 99 | 100 | "vec4 x = x_ *ns.x + ns.yyyy;", 101 | "vec4 y = y_ *ns.x + ns.yyyy;", 102 | "vec4 h = 1.0 - abs(x) - abs(y);", 103 | 104 | "vec4 b0 = vec4( x.xy, y.xy );", 105 | "vec4 b1 = vec4( x.zw, y.zw );", 106 | 107 | //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; 108 | //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; 109 | "vec4 s0 = floor(b0)*2.0 + 1.0;", 110 | "vec4 s1 = floor(b1)*2.0 + 1.0;", 111 | "vec4 sh = -step(h, vec4(0.0));", 112 | 113 | "vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;", 114 | "vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;", 115 | 116 | "vec3 p0 = vec3(a0.xy,h.x);", 117 | "vec3 p1 = vec3(a0.zw,h.y);", 118 | "vec3 p2 = vec3(a1.xy,h.z);", 119 | "vec3 p3 = vec3(a1.zw,h.w);", 120 | 121 | //Normalise gradients 122 | "vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));", 123 | "p0 *= norm.x;", 124 | "p1 *= norm.y;", 125 | "p2 *= norm.z;", 126 | "p3 *= norm.w;", 127 | 128 | // Mix final noise value 129 | "vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);", 130 | "m = m * m;", 131 | "return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1),", 132 | " dot(p2,x2), dot(p3,x3) ) );", 133 | "}", 134 | 135 | "void main(void) {", 136 | "vec3 vTextureCoord3D = vec3(vTextureCoord, uz);", 137 | "vec3 uvw = vTextureCoord3D + 0.1*vec3(snoise(vTextureCoord3D + vec3(0.0, 0.0, time)),", 138 | "snoise(vTextureCoord3D + vec3(43.0, 17.0, time)),", 139 | "snoise(vTextureCoord3D + vec3(-17.0, -43.0, time)));", 140 | // Six components of noise in a fractal sum 141 | "float n = snoise(uvw - vec3(0.0, 0.0, time));", 142 | "n += 0.5 * snoise(uvw * 2.0 - vec3(0.0, 0.0, time*1.4));", 143 | "n += 0.25 * snoise(uvw * 4.0 - vec3(0.0, 0.0, time*2.0));", 144 | "n += 0.125 * snoise(uvw * 8.0 - vec3(0.0, 0.0, time*2.8));", 145 | "n += 0.0625 * snoise(uvw * 16.0 - vec3(0.0, 0.0, time*4.0));", 146 | "n += 0.03125 * snoise(uvw * 32.0 - vec3(0.0, 0.0, time*5.6));", 147 | "n = n * amount;", 148 | // Overlay to the texture 149 | "vec4 color = texture2D(uSampler, vTextureCoord);", 150 | "gl_FragColor = color + vec4(vec3(n, n, n), color.a * 1.0);", 151 | "}" 152 | ]; 153 | 154 | }; 155 | 156 | Phaser.Filter.SNoise.prototype = Object.create(Phaser.Filter.prototype); 157 | Phaser.Filter.SNoise.prototype.constructor = Phaser.Filter.SNoise; 158 | 159 | Object.defineProperty(Phaser.Filter.SNoise.prototype, 'z', { 160 | 161 | get: function() { 162 | return this.uniforms.z.value; 163 | }, 164 | 165 | set: function(value) { 166 | this.uniforms.z.value = Math.max(0, Math.min(value, 1)); 167 | } 168 | 169 | }); 170 | 171 | Object.defineProperty(Phaser.Filter.SNoise.prototype, 'amount', { 172 | 173 | get: function() { 174 | return this.uniforms.amount.value; 175 | }, 176 | 177 | set: function(value) { 178 | this.uniforms.amount.value = Math.max(0, Math.min(value, 1)); 179 | } 180 | 181 | }); -------------------------------------------------------------------------------- /src/FilmGrain.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @filter Film Grain 4 | * 5 | * Original shader by Martins Upitis 6 | * 7 | * http://devlog-martinsh.blogspot.fi/2013/05/image-imperfections-and-film-grain-post.html 8 | * 9 | * Converted to Phaser/PIXI by Jouni Airaksinen, jouni.airaksinen@sc5.io 10 | * 11 | */ 12 | /* 13 | Film Grain post-process shader v1.1 14 | Martins Upitis (martinsh) devlog-martinsh.blogspot.com 15 | 2013 16 | 17 | -------------------------- 18 | This work is licensed under a Creative Commons Attribution 3.0 Unported License. 19 | So you are free to share, modify and adapt it for your needs, and even use it for commercial use. 20 | I would also love to hear about a project you are using it. 21 | 22 | Have fun, 23 | Martins 24 | -------------------------- 25 | 26 | Perlin noise shader by toneburst: 27 | http://machinesdontcare.wordpress.com/2009/06/25/3d-perlin-noise-sphere-vertex-shader-sourcecode/ 28 | */ 29 | 30 | Phaser.Filter.FilmGrain = function (game) { 31 | 32 | Phaser.Filter.call(this, game); 33 | 34 | this.uniforms.lumAmount = { type: '1f', value: 1.0 }; 35 | this.uniforms.grainSize = { type: '1f', value: 0.1 }; 36 | this.uniforms.grainAmount = { type: '1f', value: 0.05 }; 37 | this.uniforms.colorAmount = { type: '1f', value: 0.0 }; 38 | 39 | this.fragmentSrc = [ 40 | "precision mediump float;", 41 | "uniform float time;", 42 | "uniform sampler2D uSampler;", 43 | "uniform vec2 resolution;", 44 | "uniform float colorAmount;", 45 | "uniform float grainAmount;", 46 | "uniform float grainSize;", 47 | "uniform float lumAmount;", 48 | "varying vec2 vTextureCoord;", 49 | 50 | "const float permTexUnit = 1.0/256.0;", // Perm texture texel-size 51 | "const float permTexUnitHalf = 0.5/256.0;", // Half perm texture texel-size 52 | 53 | // As time progresses, the random starts to produce artifacts, rotate time in range 54 | // which is still fine, thus the grain loops every 120 seconds 55 | "float modTime = time - floor(time * (1.0 / 120.0)) * 120.0;", 56 | 57 | "float width = resolution.x;", 58 | "float height = resolution.y;", 59 | 60 | "bool colored = colorAmount > 0.0;", 61 | "float grainsize = 1.5 + grainSize;", //grain particle size (1.5 - 2.5) 62 | 63 | //a random texture generator, but you can also use a pre-computed perturbation texture 64 | "vec4 rnm(in vec2 tc) {", 65 | "float noise = sin(dot(tc + vec2(modTime,modTime),vec2(12.9898,78.233))) * 43758.5453;", 66 | 67 | "float noiseR = fract(noise)*2.0-1.0;", 68 | "float noiseG = fract(noise*1.2154)*2.0-1.0;", 69 | "float noiseB = fract(noise*1.3453)*2.0-1.0;", 70 | "float noiseA = fract(noise*1.3647)*2.0-1.0;", 71 | 72 | "return vec4(noiseR,noiseG,noiseB,noiseA);", 73 | "}", 74 | 75 | "float fade(in float t) {", 76 | "return t*t*t*(t*(t*6.0-15.0)+10.0);", 77 | "}", 78 | 79 | // TODO: replace to simplex from SNoise? 80 | "float pnoise3D(in vec3 p) {", 81 | "vec3 pi = permTexUnit*floor(p)+permTexUnitHalf;", // Integer part, scaled so +1 moves permTexUnit texel 82 | // and offset 1/2 texel to sample texel centers 83 | "vec3 pf = fract(p);", // Fractional part for interpolation 84 | 85 | // Noise contributions from (x=0, y=0), z=0 and z=1 86 | "float perm00 = rnm(pi.xy).a;", 87 | "vec3 grad000 = rnm(vec2(perm00, pi.z)).rgb * 4.0 - 1.0;", 88 | "float n000 = dot(grad000, pf);", 89 | "vec3 grad001 = rnm(vec2(perm00, pi.z + permTexUnit)).rgb * 4.0 - 1.0;", 90 | "float n001 = dot(grad001, pf - vec3(0.0, 0.0, 1.0));", 91 | 92 | // Noise contributions from (x=0, y=1), z=0 and z=1 93 | "float perm01 = rnm(pi.xy + vec2(0.0, permTexUnit)).a ;", 94 | "vec3 grad010 = rnm(vec2(perm01, pi.z)).rgb * 4.0 - 1.0;", 95 | "float n010 = dot(grad010, pf - vec3(0.0, 1.0, 0.0));", 96 | "vec3 grad011 = rnm(vec2(perm01, pi.z + permTexUnit)).rgb * 4.0 - 1.0;", 97 | "float n011 = dot(grad011, pf - vec3(0.0, 1.0, 1.0));", 98 | 99 | // Noise contributions from (x=1, y=0), z=0 and z=1 100 | "float perm10 = rnm(pi.xy + vec2(permTexUnit, 0.0)).a ;", 101 | "vec3 grad100 = rnm(vec2(perm10, pi.z)).rgb * 4.0 - 1.0;", 102 | "float n100 = dot(grad100, pf - vec3(1.0, 0.0, 0.0));", 103 | "vec3 grad101 = rnm(vec2(perm10, pi.z + permTexUnit)).rgb * 4.0 - 1.0;", 104 | "float n101 = dot(grad101, pf - vec3(1.0, 0.0, 1.0));", 105 | 106 | // Noise contributions from (x=1, y=1), z=0 and z=1 107 | "float perm11 = rnm(pi.xy + vec2(permTexUnit, permTexUnit)).a ;", 108 | "vec3 grad110 = rnm(vec2(perm11, pi.z)).rgb * 4.0 - 1.0;", 109 | "float n110 = dot(grad110, pf - vec3(1.0, 1.0, 0.0));", 110 | "vec3 grad111 = rnm(vec2(perm11, pi.z + permTexUnit)).rgb * 4.0 - 1.0;", 111 | "float n111 = dot(grad111, pf - vec3(1.0, 1.0, 1.0));", 112 | 113 | // Blend contributions along x 114 | "vec4 n_x = mix(vec4(n000, n001, n010, n011), vec4(n100, n101, n110, n111), fade(pf.x));", 115 | 116 | // Blend contributions along y 117 | "vec2 n_xy = mix(n_x.xy, n_x.zw, fade(pf.y));", 118 | 119 | // Blend contributions along z 120 | "float n_xyz = mix(n_xy.x, n_xy.y, fade(pf.z));", 121 | 122 | // We're done, return the final noise value. 123 | "return n_xyz;", 124 | "}", 125 | 126 | //2d coordinate orientation thing 127 | "vec2 coordRot(in vec2 tc, in float angle) {", 128 | "float aspect = width/height;", 129 | "float rotX = ((tc.x*2.0-1.0)*aspect*cos(angle)) - ((tc.y*2.0-1.0)*sin(angle));", 130 | "float rotY = ((tc.y*2.0-1.0)*cos(angle)) + ((tc.x*2.0-1.0)*aspect*sin(angle));", 131 | "rotX = ((rotX/aspect)*0.5+0.5);", 132 | "rotY = rotY*0.5+0.5;", 133 | "return vec2(rotX,rotY);", 134 | "}", 135 | 136 | "float rand() {", 137 | "return fract(cos(dot(vec2(modTime, modTime), vec2(12.9898, 4.1414))) * 43758.5453);", 138 | "}", 139 | 140 | // Main filter 141 | "void main(void) {", 142 | 143 | "vec2 rotCoordsR = coordRot(vTextureCoord, 0.05*rand() + 1.1087);", 144 | //"vec2 rotCoordsR = vTextureCoord;", 145 | "vec3 noise = vec3(pnoise3D(vec3(rotCoordsR*vec2(width/grainsize,height/grainsize),0.0)));", 146 | 147 | "if (colored) {", 148 | "vec2 rotCoordsG = coordRot(vTextureCoord, 0.06*rand() + 1.1087);", 149 | "vec2 rotCoordsB = coordRot(vTextureCoord, 0.07*rand() + 1.1087);", 150 | "noise.g = mix(noise.r,pnoise3D(vec3(rotCoordsG*vec2(width/grainsize,height/grainsize),1.0)),colorAmount);", 151 | "noise.b = mix(noise.r,pnoise3D(vec3(rotCoordsB*vec2(width/grainsize,height/grainsize),2.0)),colorAmount);", 152 | "}", 153 | 154 | "vec4 color = texture2D(uSampler, vTextureCoord);", 155 | "vec3 col = color.rgb;", 156 | 157 | //noisiness response curve based on scene luminance 158 | "vec3 lumcoeff = vec3(0.299,0.587,0.114);", 159 | "float luminance = mix(0.0,dot(col, lumcoeff),lumAmount);", 160 | "float lum = smoothstep(0.2,0.0,luminance);", 161 | "lum += luminance;", 162 | 163 | "noise = mix(noise,vec3(0.0),pow(lum,4.0));", 164 | "col = col + noise*grainAmount;", 165 | 166 | "gl_FragColor = vec4(col, color.a);", 167 | "}" 168 | ]; 169 | 170 | }; 171 | 172 | Phaser.Filter.FilmGrain.prototype = Object.create(Phaser.Filter.prototype); 173 | Phaser.Filter.FilmGrain.prototype.constructor = Phaser.Filter.FilmGrain; 174 | 175 | Phaser.Filter.FilmGrain.prototype.init = function (width, height) { 176 | this.setResolution(width || this.game.width, height || this.game.height); 177 | }; 178 | 179 | Object.defineProperty(Phaser.Filter.FilmGrain.prototype, 'color', { 180 | 181 | get: function() { 182 | return this.uniforms.colorAmount.value; 183 | }, 184 | 185 | set: function(value) { 186 | this.uniforms.colorAmount.value = Math.max(0, Math.min(value, 1)); 187 | } 188 | 189 | }); 190 | Object.defineProperty(Phaser.Filter.FilmGrain.prototype, 'luminance', { 191 | 192 | get: function() { 193 | return this.uniforms.lumAmount.value; 194 | }, 195 | 196 | set: function(value) { 197 | this.uniforms.lumAmount.value = value; 198 | } 199 | 200 | }); 201 | Object.defineProperty(Phaser.Filter.FilmGrain.prototype, 'size', { 202 | 203 | get: function() { 204 | return this.uniforms.grainSize.value; 205 | }, 206 | 207 | set: function(value) { 208 | this.uniforms.grainSize.value = Math.max(0, Math.min(value, 1)); 209 | } 210 | 211 | }); 212 | Object.defineProperty(Phaser.Filter.FilmGrain.prototype, 'amount', { 213 | 214 | get: function() { 215 | return this.uniforms.grainAmount.value; 216 | }, 217 | 218 | set: function(value) { 219 | this.uniforms.grainAmount.value = Math.max(0, Math.min(value, 1)); 220 | } 221 | 222 | }); --------------------------------------------------------------------------------