├── .gitignore
├── .npmignore
├── .travis.yml
├── LICENSE
├── README.md
├── assets
├── ASSETS.md
├── Storm Cell Over the Southern Appalachian Mountains-dsc_2303_0-256x256.png
├── result-256x256x-r1.png
├── result-256x256x-r16.png
├── result-256x256x-r2.png
├── result-256x256x-r4.png
└── result-256x256x-r8.png
├── glsl-gaussian-demo.js
├── glsl-gaussian-live-demo.js
├── glsl-gaussian.js
├── package.json
└── scripts
├── build-a-demo.js
├── build-demo.js
├── build-live-demo.js
└── publish-static-demos.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | npm-debug.log
2 | node_modules/*
3 | *.DS_Store
4 | coverage/*
5 | bench/*.html
6 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | bench/*
2 | example/*
3 | test/*
4 | www/*
5 | bin/*
6 | dist/*
7 | coverage/*
8 | images/*
9 | compare/*
10 | CNAME
11 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: required
2 | language: node_js
3 | node_js:
4 | - '6.3'
5 | env:
6 | global:
7 | - CXX=g++-4.8
8 | #GH_TOKEN
9 | - secure: >-
10 | QxB0SfVV0ODqdhNSSkLwxX3ZKry9lTWHaxG3Q7kNeLwq8pMhc11USzq7WYOpHWpwuTyv//XUs53jAl77jaAgizuUE8O3oSemaoH+x2ycRiOFx7Vto46OiTm2vrqqy0GCblk8FNsny3Pkc+Otm9sNiOjDWdJYrZe9t4s4Rm2HMAvvoilpTU92K+0ANPIqfwyZYJbvx0Rn8vLAe32wOH1KD9ZwvJAfDcTyiF0iouVH6raXwa8t2nWVg0VY9dpnyraoRmchmpbsc1KmFnr+O9iGcZXPzMMG9cO+riKEDL29l/6p+QaKfipbpkBQlWecwxtrHpPKpWBBofSMGuPdmOzbE5i4WIAajgtOCBgctOsRmH894ExQ4A40ZSL6wguK/1Vl2bi9EvR6eQ2OwXSuYwABbhXSWepNOGJGodxXNw3IAlEszS/VlVoiPmaUxfaDa0esXN42YTtXgPXqdchnDQQOrphxQmCzuYUzoXywq+KOytdy8fbk1POYdRR92Pg4iVQn4bvxyBqraBaFGmtSufLFaOi4l/Sfu+VZMBrVog3WjslgWiUrDVmWFKbtDQbup8G/AsHmp4DLiRNrUuMDuz2NH0q7t7WkZLr4+N+BBbmqUWUVSx1ZX/UrV8bOkTpu10YOANihXeK7B3XjXG5a3NVxtDkFb1oSaj1MrkODut4rcJI=
11 | addons:
12 | apt:
13 | sources:
14 | - ubuntu-toolchain-r-test
15 | packages:
16 | - g++-4.8
17 | install:
18 | - npm install --global browserify
19 | - npm install
20 | script:
21 | - npm run mytest
22 | - npm run build
23 | - bash scripts/publish-static-demos.sh
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Azriel Fasten
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | glsl-gaussian
3 | ---
4 |
5 |
6 | ####Description
7 |
8 | glsl-gaussian is a shader generator for WebGL, to generate a gaussian blur of an input texture.
9 |
10 |
11 | See `glsl-gaussian-live-demo.js`, `glsl-gaussian-demo.js` for usage.
12 |
13 | ####Dependencies
14 |
15 | * nodejs
16 | * browserify
17 | * [glsl-quad](https://github.com/realazthat/glsl-quad)
18 | * [glsl-sat](https://github.com/realazthat/glsl-sat)
19 | * [regl](https://github.com/mikolalysenko/regl)
20 | * [glsl-numerify](https://github.com/realazthat/glsl-numerify) (for demo)
21 | * [resl](https://github.com/mikolalysenko/resl) (for demo)
22 | * budo (for quick demo as an alternative to running browserify)
23 |
24 |
25 | ####Demo
26 |
27 | To run the demo, run:
28 |
29 | ```
30 | cd ./glsl-gaussian
31 |
32 | #install npm dependencies
33 | npm install
34 |
35 | #browser should open with the demo
36 | budo glsl-gaussian-demo.js --open
37 |
38 | #browser should open with the demo
39 | budo glsl-gaussian-live-demo.js --open
40 |
41 | ```
42 |
43 | **Live:**
44 |
45 | branch | demo
46 | --------|-------
47 | master | [glsl-gaussian-demo](https://realazthat.github.io/glsl-gaussian/master/www/glsl-gaussian-demo/index.html)
48 | | [glsl-gaussian-live-demo](https://realazthat.github.io/glsl-gaussian/master/www/glsl-gaussian-live-demo/index.html)
49 | develop | [glsl-gaussian-demo](https://realazthat.github.io/glsl-gaussian/develop/www/glsl-gaussian-demo/index.html)
50 | | [glsl-gaussian-live-demo](https://realazthat.github.io/glsl-gaussian/develop/www/glsl-gaussian-live-demo/index.html)
51 |
52 | **Results:**
53 |
54 | (Image credit: [Storm Cell Over the Southern Appalachian Mountains](http://www.nasa.gov/content/storm-cell-over-the-southern-appalachian-mountains),
55 | *NASA / Stu Broce*, public domain by virtue of being created by NASA)
56 |
57 | Source Image |
58 | --------------|
59 |
60 |
61 | Gaussian Blur with radius 1 | Gaussian Blur with radius 2 | Gaussian Blur with radius 4 |
62 | ------------------------------|-----------------------------|-----------------------------|
63 |
|
|
|
64 |
65 |
66 | ####Docs
67 |
68 | ```
69 | const gaussian = require('./glsl-gaussian.js');
70 | ```
71 |
72 | ##### `gaussian.blur.gaussian.compute ({regl, texture, radius, fbos, currentFboIndex = 0, boxPasses = 3, outFbo = null, components = 'rgba', type = 'vec4', clipY = 1})`
73 |
74 | * Computes the guassian blur of the given texture.
75 | * `regl` - a regl context.
76 | * `radius` - The radius of the gaussian blur; that is to say, the kernel window around the pixel will be of size `(2*radius+1)X(2*radius+1)`.
77 | * `fbos` - an array with at least 2 regl FBOs, used for ping-ponging during processing; should prolly have
78 | a type of float (32-bit) for each channel.
79 | * `currentFboIndex` the regl FBO index in `fbos` array to begin at for ping-ponging. The function will begin by incrementing this
80 | value and using the next FBO in the array. The function will return a value in the form of
81 | `{currentFboIndex}` with the position of the last-used FBO. Defaults to `0`.
82 | * `outFbo` - destination regl FBO. Can be null, in which case the result will be left inside the `fbos` array
83 | on the last ping-pong; the return value with be of the form `{currentFboIndex}` so that you
84 | can retrieve it.
85 | * `components` - a string indicating which components need to be processed and blurred; defaults to `'rgba'`.
86 | * `type` - a glsl type in string format indicating the type that can hold the components that need to be processed; defaults to `'vec4'`.
87 | * `clipY` - a value that represents the clipspace y multiple; a default value of `1` indicates opengl-style lower-left-corner-as-origin;
88 | a value of `-1` would mean a upper-left-corner-as-origin.
89 |
90 |
91 |
92 | ##### `gaussian.blur.box.shader.vert ({textureWidth, textureHeight, radius, components = 'rgba', type = 'vec4'})`
93 |
94 | * Generate a vertex shader that computes the box blur from a Summed Area Table texture.
95 | Returns the vertex shader as a string.
96 | * `textureWidth` - The width of the inputtexture.
97 | * `textureHeight` - The height of the input texture.
98 | * `radius` - The radius of the box blur; that is to say, the box around the pixel will be of size `(2*radius+1)X(2*radius+1)`.
99 | * `components` - a string indicating which components need to be processed and blurred; defaults to `'rgba'`.
100 | * `type` - a glsl type in string format indicating the type that can hold the components that need to be processed; defaults to `'vec4'`.
101 |
102 |
103 |
104 | ##### `gaussian.blur.box.shader.frag ({textureWidth, textureHeight, radius, components = 'rgba', type = 'vec4'})`
105 |
106 | * Generate a fragment shader that computes the box blur from a Summed Area Table texture.
107 | Returns the fragment shader as a string.
108 | * See `gaussian.box.shader.vert()` for params.
109 |
110 | ##### `gaussian.blur.box.compute ({regl, src, radius, outFbo = null, components = 'rgba', type = 'vec4', clipY = 1})`
111 |
112 | * Given an input texture, will compute the box blur.
113 | * `regl` - a regl context.
114 | * `src` - A dictionary of the form `{satTexture}` OR `{texture, fbos, currentFboIndex}`.
115 | * In the first form, the Summed Area Table
116 | is provided by you, the user. No FBOs are needed, just be sure to specify the `outFbo` argument.
117 | * In the second form, you provide the input texture yourself (via the `texture` argument), and FBOs
118 | for pingponging during computation of SAT. The FBOs should be an array of at least 2. The FBOs
119 | should prolly be of a high precision type (such as float 32 bit). `currentFboIndex` will be
120 | returned in the form `{currentFboIndex}` representing the last-used FBO. If `outFbo` is not
121 | specified, then this FBO slot will hold the result of the blur.
122 | * `radius` - The radius of the box blur; that is to say, the box around the pixel will be of size (2*radius+1).
123 | * `outFbo` - Destination regl FBO. Can be null, in which case `src.fbos` is expected to exist; the result of
124 | of the computation will be left inside the `src.fbos` array on the last ping-pong; the return
125 | value with be of the form `{currentFboIndex}` so that you can retrieve it.
126 | * `components` - a string indicating which components need to be processed and blurred; defaults to `'rgba'`.
127 | * `type` - a glsl type in string format indicating the type that can hold the components that need to be processed; defaults to `'vec4'`.
128 | * `clipY` - a value that represents the clipspace y multiple; a default value of `1` indicates opengl-style lower-left-corner-as-origin;
129 | a value of `-1` would mean a upper-left-corner-as-origin.
130 |
131 |
132 | ####Usage
133 |
134 | See `glsl-gaussian-demo.js` for a full demo using [regl](https://github.com/mikolalysenko/regl)
135 | and [resl](https://github.com/mikolalysenko/resl).
136 |
137 | An excerpt:
138 |
139 | ```
140 |
141 | gaussian.blur.gaussian.compute({regl, texture, radius, fbos, outFbo, components: 'rgb', type: 'vec3'});
142 |
143 |
144 | ```
145 |
146 |
147 |
--------------------------------------------------------------------------------
/assets/ASSETS.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | See [wikimedia commons on policy of accepting public domain from NASA](https://commons.wikimedia.org/wiki/Template:PD-USGov-NASA).
4 |
5 | * `Storm Cell Over the Southern Appalachian Mountains-dsc_2303_0-256x256.jpg`
6 | Public Domain, from NASA: [Storm Cell Over the Southern Appalachian Mountains](http://www.nasa.gov/content/storm-cell-over-the-southern-appalachian-mountains)
7 |
--------------------------------------------------------------------------------
/assets/Storm Cell Over the Southern Appalachian Mountains-dsc_2303_0-256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realazthat/glsl-gaussian/dbc39183d41f9e69d4211d623251ac5956c24a64/assets/Storm Cell Over the Southern Appalachian Mountains-dsc_2303_0-256x256.png
--------------------------------------------------------------------------------
/assets/result-256x256x-r1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realazthat/glsl-gaussian/dbc39183d41f9e69d4211d623251ac5956c24a64/assets/result-256x256x-r1.png
--------------------------------------------------------------------------------
/assets/result-256x256x-r16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realazthat/glsl-gaussian/dbc39183d41f9e69d4211d623251ac5956c24a64/assets/result-256x256x-r16.png
--------------------------------------------------------------------------------
/assets/result-256x256x-r2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realazthat/glsl-gaussian/dbc39183d41f9e69d4211d623251ac5956c24a64/assets/result-256x256x-r2.png
--------------------------------------------------------------------------------
/assets/result-256x256x-r4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realazthat/glsl-gaussian/dbc39183d41f9e69d4211d623251ac5956c24a64/assets/result-256x256x-r4.png
--------------------------------------------------------------------------------
/assets/result-256x256x-r8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realazthat/glsl-gaussian/dbc39183d41f9e69d4211d623251ac5956c24a64/assets/result-256x256x-r8.png
--------------------------------------------------------------------------------
/glsl-gaussian-demo.js:
--------------------------------------------------------------------------------
1 |
2 | const $ = require('jquery-browserify');
3 | const resl = require('resl');
4 | const regl = require('regl')({
5 | extensions: ['OES_texture_float'],
6 | // TODO: FIXME: dunno why we need this here, we do not read non-uint8 data from screen,
7 | // but it fails without this on gh-pages for some reason.
8 | attributes: {preserveDrawingBuffer: true}
9 | });
10 |
11 | const gaussian = require('./glsl-gaussian.js');
12 | const quad = require('glsl-quad');
13 |
14 | // command to copy a texture to an FBO, assumes the texture is in opengl-order
15 | // where the origin is the lower left of the texture.
16 | const drawTextureToFbo = regl({
17 | frag: quad.shader.frag,
18 | vert: quad.shader.vert,
19 | attributes: {
20 | a_position: quad.verts,
21 | a_uv: quad.uvs
22 | },
23 | elements: quad.indices,
24 | uniforms: {
25 | u_tex: regl.prop('texture'),
26 | u_clip_y: 1
27 | },
28 | framebuffer: regl.prop('fbo')
29 | });
30 |
31 | // command to copy a texture to an FBO, but flipping the Y axis so that the uvs begin
32 | // at the upper right corner, so that it can be drawn to canvas etc.
33 | const drawToCanvasFBO = regl({
34 | frag: quad.shader.frag,
35 | vert: quad.shader.vert,
36 | attributes: {
37 | a_position: quad.verts,
38 | a_uv: quad.uvs
39 | },
40 | elements: quad.indices,
41 | uniforms: {
42 | u_tex: regl.prop('texture'),
43 | u_clip_y: -1
44 | },
45 | framebuffer: regl.prop('fbo')
46 | });
47 |
48 | function dataURIFromFBO ({fbo, width, height, regl}) {
49 | let canvasFBO = regl.framebuffer({
50 | color: regl.texture({
51 | width: width,
52 | height: height,
53 | stencil: false,
54 | format: 'rgba',
55 | type: 'uint8',
56 | depth: false,
57 | wrap: 'clamp',
58 | mag: 'nearest',
59 | min: 'nearest'
60 | })
61 | });
62 |
63 | let data = [];
64 | try {
65 | drawToCanvasFBO({texture: fbo.color[0], fbo: canvasFBO});
66 |
67 | let bindFbo = regl({framebuffer: canvasFBO});
68 | bindFbo(function () {
69 | data = regl.read();
70 | });
71 | } finally {
72 | canvasFBO.destroy();
73 | }
74 |
75 | var canvas = document.createElement('canvas');
76 | canvas.width = width;
77 | canvas.height = height;
78 | var context = canvas.getContext('2d');
79 |
80 | // Copy the pixels to a 2D canvas
81 | var imageData = context.createImageData(width, height);
82 | imageData.data.set(data);
83 | context.putImageData(imageData, 0, 0);
84 |
85 | return canvas.toDataURL();
86 | }
87 |
88 | resl({
89 | manifest: {
90 | texture: {
91 | type: 'image',
92 | src: './assets/Storm Cell Over the Southern Appalachian Mountains-dsc_2303_0-256x256.png',
93 | parser: (data) => regl.texture({
94 | data: data,
95 | mag: 'nearest',
96 | min: 'nearest',
97 | flipY: true
98 | })
99 | }
100 | },
101 | onDone: ({texture, digitsTexture}) => {
102 | // make a bunch of fbos for ping-ponging intermediate computations, and the output buffer etc.
103 | let fbos = [null, null, null, null].map(function () {
104 | return regl.framebuffer({
105 | color: regl.texture({
106 | width: texture.width,
107 | height: texture.height,
108 | stencil: false,
109 | format: 'rgba',
110 | type: 'float',
111 | depth: false,
112 | wrap: 'clamp',
113 | mag: 'nearest',
114 | min: 'nearest'
115 | }),
116 | stencil: false,
117 | depth: false,
118 | depthStencil: false,
119 | wrap: 'clamp',
120 | mag: 'nearest',
121 | min: 'nearest'
122 | });
123 | });
124 |
125 | // use one FBO for the output.
126 | let outFbo = fbos.pop();
127 |
128 | // and another for the input, for later use.
129 | let inFbo = fbos.pop();
130 |
131 | let radius = 1;
132 | gaussian.blur.gaussian.compute({regl, texture, radius, fbos, outFbo: outFbo, components: 'rgb', type: 'vec3'});
133 |
134 | let upscaledCellWidth = 16;
135 | let upscaledCellHeight = 16;
136 | let upscaledWidth = texture.width * Math.max(upscaledCellWidth, upscaledCellHeight);
137 | let upscaledHeight = texture.height * Math.max(upscaledCellWidth, upscaledCellHeight);
138 |
139 | // copy the input texture to the `inFbo`.
140 | drawTextureToFbo({texture, fbo: inFbo});
141 |
142 | // draw the stuff to img tags, and put everything into the DOM for display.
143 |
144 | let $srcDiv = $('
Radius | 94 |95 | | 96 | |
FPS (approximate rolling average) | 99 |100 | | 101 | |