├── .gitignore
├── .npmignore
├── test
├── bunny.frag
├── smokestack.js
├── bunny.vert
├── test.frag
└── index.js
├── index.html
├── post.vert
├── example
├── bunny.frag
├── post.frag
├── bunny.vert
└── index.js
├── LICENSE.md
├── index.js
├── package.json
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | *.log
3 | .DS_Store
4 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | *.log
3 | .DS_Store
4 | bundle.js
5 | test
6 | test.js
7 | example
8 |
--------------------------------------------------------------------------------
/test/bunny.frag:
--------------------------------------------------------------------------------
1 | precision mediump float;
2 |
3 | void main() {
4 | gl_FragColor = vec4(1);
5 | }
6 |
--------------------------------------------------------------------------------
/test/smokestack.js:
--------------------------------------------------------------------------------
1 | require('./index')
2 | require('tape')('shutdown', function(t) {
3 | t.end()
4 | setTimeout(function(){window.close()})
5 | })
6 |
--------------------------------------------------------------------------------
/test/bunny.vert:
--------------------------------------------------------------------------------
1 | precision mediump float;
2 | attribute vec3 position;
3 | uniform mat4 proj;
4 | uniform mat4 view;
5 | void main() {
6 | gl_Position = proj * view * vec4(position, 1.0);
7 | }
8 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | gl-post
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/post.vert:
--------------------------------------------------------------------------------
1 | precision mediump float;
2 |
3 | attribute vec2 position;
4 | varying vec2 screenPosition;
5 |
6 | void main() {
7 | screenPosition = (position + 1.0) * 0.5;
8 | gl_Position = vec4(position, 1.0, 1.0);
9 | }
10 |
--------------------------------------------------------------------------------
/test/test.frag:
--------------------------------------------------------------------------------
1 | precision mediump float;
2 |
3 | uniform sampler2D colorBuffer;
4 | uniform float t;
5 |
6 | varying vec2 screenPosition;
7 |
8 | void main() {
9 | gl_FragColor = texture2D(colorBuffer, screenPosition);
10 | }
11 |
--------------------------------------------------------------------------------
/example/bunny.frag:
--------------------------------------------------------------------------------
1 | precision mediump float;
2 |
3 | // Sets the color of the current fragment (pixel)
4 | // to display the normal at the current position.
5 | // Using `abs()` to prevent negative values, which
6 | // would just end up being black.
7 |
8 | varying vec3 vNormal;
9 |
10 | void main() {
11 | gl_FragColor = vec4(abs(vNormal), 1.0);
12 | }
13 |
--------------------------------------------------------------------------------
/example/post.frag:
--------------------------------------------------------------------------------
1 | precision mediump float;
2 |
3 | uniform sampler2D colorBuffer;
4 | uniform float t;
5 |
6 | varying vec2 screenPosition;
7 |
8 | void main() {
9 | // Here we're changing the texture sample coordinates
10 | // to get a distorted image.
11 | vec2 samplePosition = screenPosition;
12 |
13 | samplePosition = (sin(screenPosition * 15.0) + 1.0) * 0.5;
14 | samplePosition = samplePosition + (cos(t) + 1.0) * 0.25;
15 |
16 | vec4 sampleColor = texture2D(colorBuffer, samplePosition);
17 |
18 | gl_FragColor = vec4(sampleColor.rgb, 1);
19 | }
20 |
--------------------------------------------------------------------------------
/example/bunny.vert:
--------------------------------------------------------------------------------
1 | // Our vertex shader is run once for each of these
2 | // vectors, to determine the final position of the vertex
3 | // on the screen and pass data off to the fragment shader.
4 |
5 | precision mediump float;
6 |
7 | // Our attributes, i.e. the arrays of vectors in the bunny mesh.
8 | attribute vec3 aPosition;
9 | attribute vec3 aNormal;
10 |
11 | // This is passed from here to be used in `bunny.frag`.
12 | varying vec3 vNormal;
13 |
14 | uniform mat4 uProjection;
15 | uniform mat4 uModel;
16 | uniform mat4 uView;
17 |
18 | void main() {
19 | vNormal = aNormal;
20 |
21 | // - `uProjection` will apply our perspective matrix, and
22 | // - `uView` will apply our camera transforms.
23 | // - `uModel` is unused here, but is traditionally used to
24 | // move the object around the scene.
25 | gl_Position = uProjection * uView * uModel * vec4(aPosition, 1.0);
26 | }
27 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | =====================
3 |
4 | Copyright (c) 2014 [stackgl](http://github.com/stackgl/) contributors
5 |
6 | *stackgl contributors listed at *
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 |
12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var triangle = require('a-big-triangle')
2 | var FBO = require('gl-fbo')
3 |
4 | module.exports = Post
5 |
6 | function Post(gl, shader, opts) {
7 | if (!(this instanceof Post)) return new Post(gl, shader, opts)
8 |
9 | opts = opts || {}
10 | shader = typeof shader === 'function'
11 | ? shader(gl)
12 | : shader
13 |
14 | this.gl = gl
15 | this.canvas = gl.canvas
16 | this.shader = shader
17 | this.shader.attributes.position.location = 0
18 |
19 | this._colorBufferName = opts.colorBufferName || 'colorBuffers'
20 |
21 | this.fbo = FBO(gl, [gl.drawingBufferWidth, gl.drawingBufferHeight])
22 | this.fbo.color[0].minFilter = opts.minFilter || gl.LINEAR
23 | this.fbo.color[0].magFilter = opts.magFilter || gl.LINEAR
24 | }
25 |
26 | var dims = [0, 0]
27 |
28 | Post.prototype.bind = function() {
29 | var gl = this.gl
30 |
31 | dims[0] = gl.drawingBufferWidth
32 | dims[1] = gl.drawingBufferHeight
33 |
34 | this.fbo.bind()
35 | this.fbo.shape = dims
36 | }
37 |
38 | Post.prototype.unbind = function() {
39 | this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, null)
40 | }
41 |
42 | Post.prototype.draw = function() {
43 | var gl = this.gl
44 |
45 | this.unbind()
46 |
47 | gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight)
48 | gl.disable(gl.DEPTH_TEST)
49 | gl.disable(gl.CULL_FACE)
50 |
51 | this.shader.bind()
52 | this.shader.uniforms[this._colorBufferName] = this.fbo.color[0].bind(0)
53 |
54 | triangle(gl)
55 | }
56 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gl-post",
3 | "version": "1.0.1",
4 | "description": "Simple WebGL post-processing",
5 | "main": "index.js",
6 | "glslify": "post.vert",
7 | "license": "MIT",
8 | "scripts": {
9 | "start": "beefy example/index.js:bundle.js --open -- -t glslify",
10 | "bundle": "browserify -t glslify example/index.js -o bundle.js",
11 | "test": "npm run test:chrome && npm run test:firefox",
12 | "test:chrome": "browserify -t glslify test/smokestack.js | smokestack -b chrome | tap-spec",
13 | "test:firefox": "browserify -t glslify test/smokestack.js | smokestack -b firefox | tap-spec"
14 | },
15 | "author": {
16 | "name": "Hugh Kennedy",
17 | "email": "hughskennedy@gmail.com",
18 | "url": "http://hughsk.io/"
19 | },
20 | "dependencies": {
21 | "a-big-triangle": "^1.0.0",
22 | "gl-fbo": "^2.0.3"
23 | },
24 | "devDependencies": {
25 | "bunny": "^1.0.1",
26 | "canvas-fit": "^1.2.0",
27 | "canvas-orbit-camera": "^1.0.1",
28 | "canvas-pixels": "0.0.0",
29 | "gl-context": "^0.1.1",
30 | "gl-geometry": "^1.0.0",
31 | "gl-mat4": "^1.0.1",
32 | "glslify": "^1.6.0",
33 | "normals": "^1.0.1",
34 | "smokestack": "^2.0.0",
35 | "tap-spec": "^2.1.0",
36 | "tape": "^3.0.3"
37 | },
38 | "repository": {
39 | "type": "git",
40 | "url": "git://github.com/stackgl/gl-post.git"
41 | },
42 | "keywords": [
43 | "post-processing",
44 | "postprocessing",
45 | "distort",
46 | "recolor",
47 | "webgl",
48 | "stackgl"
49 | ],
50 | "homepage": "https://github.com/stackgl/gl-post",
51 | "bugs": {
52 | "url": "https://github.com/stackgl/gl-post/issues"
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | var pixels = require('canvas-pixels')
2 | var Geom = require('gl-geometry')
3 | var mat4 = require('gl-mat4')
4 | var glslify = require('glslify')
5 | var glPost = require('../')
6 | var bunny = require('bunny')
7 | var test = require('tape')
8 |
9 | test('gl-post', function(t) {
10 | var canvas = document.body.appendChild(document.createElement('canvas'))
11 | var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl')
12 |
13 | var camera = require('canvas-orbit-camera')(canvas)
14 | var width = canvas.width = 300
15 | var height = canvas.height = 300
16 | var post = glPost(gl, glslify({
17 | vert: '../post.vert'
18 | , frag: './test.frag'
19 | }))
20 |
21 | var shader = glslify({
22 | vert: './bunny.vert'
23 | , frag: './bunny.frag'
24 | })(gl)
25 |
26 | var proj = mat4.create()
27 | var view = mat4.create()
28 | var geom = Geom(gl)
29 | geom.attr('position', bunny.positions)
30 | geom.faces(bunny.cells)
31 |
32 | function drawScene() {
33 | camera.distance = 17
34 | camera.center = [0, 4, 0]
35 | camera.view(view)
36 | mat4.perspective(proj, Math.PI / 4, width / height, 0.01, 100)
37 |
38 | gl.viewport(0, 0, width, height)
39 | gl.clearColor(0, 0, 0, 1)
40 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
41 |
42 | geom.bind(shader)
43 | shader.uniforms.proj = proj
44 | shader.uniforms.view = view
45 | geom.draw()
46 | }
47 |
48 | drawScene()
49 | var plain = pixels(gl)
50 |
51 | post.bind()
52 | drawScene()
53 | post.draw()
54 |
55 | var postplain = pixels(gl)
56 | var count = 0
57 |
58 | for (var i = 0; i < plain.length; i++) {
59 | if (plain[i] !== postplain[i]) count++
60 | }
61 |
62 | var error = count / plain.length
63 | var percent = (100-error*100).toFixed(2)
64 |
65 | t.ok(error <= 0.01, 'images matched! ' + percent + '% equivalent')
66 | t.end()
67 | })
68 |
--------------------------------------------------------------------------------
/example/index.js:
--------------------------------------------------------------------------------
1 | var Geometry = require('gl-geometry')
2 | var mat4 = require('gl-mat4')
3 | var normals = require('normals')
4 | var glslify = require('glslify')
5 | var bunny = require('bunny')
6 | var Post = require('../')
7 |
8 | var canvas = document.body.appendChild(document.createElement('canvas'))
9 | var gl = require('gl-context')(canvas, render)
10 | var camera = require('canvas-orbit-camera')(canvas)
11 | var start = Date.now()
12 |
13 | var post = Post(gl, glslify({
14 | vert: '../post.vert'
15 | , frag: './post.frag'
16 | }))
17 |
18 | window.addEventListener('resize'
19 | , require('canvas-fit')(canvas)
20 | , false
21 | )
22 |
23 | var geometry = Geometry(gl)
24 |
25 | geometry.attr('aPosition', bunny.positions)
26 | geometry.attr('aNormal', normals.vertexNormals(
27 | bunny.cells
28 | , bunny.positions
29 | ))
30 |
31 | geometry.faces(bunny.cells)
32 |
33 | var projection = mat4.create()
34 | var model = mat4.create()
35 | var view = mat4.create()
36 | var height
37 | var width
38 |
39 | var shader = glslify({
40 | vert: './bunny.vert'
41 | , frag: './bunny.frag'
42 | })(gl)
43 |
44 | function update() {
45 | width = gl.drawingBufferWidth
46 | height = gl.drawingBufferHeight
47 |
48 | camera.view(view)
49 | camera.tick()
50 |
51 | mat4.perspective(projection
52 | , Math.PI / 4
53 | , gl.drawingBufferWidth / gl.drawingBufferHeight
54 | , 0.01
55 | , 100
56 | )
57 | }
58 |
59 | function render() {
60 | update()
61 |
62 | post.bind()
63 |
64 | gl.viewport(0, 0, width, height)
65 | gl.clearColor(0, 0, 0, 1)
66 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
67 | gl.enable(gl.DEPTH_TEST)
68 | gl.enable(gl.CULL_FACE)
69 |
70 | geometry.bind(shader)
71 |
72 | shader.uniforms.uProjection = projection
73 | shader.uniforms.uView = view
74 | shader.uniforms.uModel = model
75 |
76 | geometry.draw(gl.TRIANGLES)
77 |
78 | post.shader.bind()
79 | post.shader.uniforms.t = (Date.now() - start) * 0.001
80 | post.draw()
81 | }
82 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # gl-post
2 | 
3 | 
4 | 
5 | 
6 |
7 | Simple WebGL post-processing using some pieces from [stackgl](http://stack.gl/).
8 |
9 | **[check out the demo](http://stack.gl/gl-post)**.
10 |
11 | ## Usage
12 |
13 | [](https://nodei.co/npm/gl-post/)
14 |
15 | See the [example](example) code for a full usage example.
16 |
17 | ### `post = glPost(gl, shader, opts={})`
18 |
19 | Creates a new post-processing instance, where `gl` is a `WebGLContext` instance
20 | and `shader` is a shader instance from either
21 | [gl-shader-core](http://github.com/mikolalysenko/gl-shader-core) or
22 | [glslify](http://github.com/stackgl/glslify).
23 |
24 | The vertex shader is supplied for you, and available at `gl-post/post.vert`.
25 | The shader you pass in may also be a function that takes a `WebGLContext` and
26 | returns a shader instance too, so the following is valid:
27 |
28 | ``` javascript
29 | var glslify = require('glslify')
30 | var glPost = require('gl-post')
31 |
32 | post = glPost(gl, glslify({
33 | vert: 'gl-post'
34 | , frag: './src/my-shader.frag'
35 | }))
36 | ```
37 |
38 | There are also a few options you can include too:
39 |
40 | * `minFilter`: the texture minification filter to use. Defaults to `gl.LINEAR`.
41 | * `magFilter`: the texture magnification filter to use. Defaults to `gl.LINEAR`.
42 | * `colorBufferName`: the name of your color buffer uniform to use in your
43 | shader. Defaults to `colorBuffer`.
44 |
45 | In simple cases, you'll want to do something like this:
46 |
47 | ``` javascript
48 | var glslify = require('glslify')
49 | var glPost = require('gl-post')
50 |
51 | post = glPost(gl, glslify({
52 | vert: 'gl-post'
53 | , frag: './src/my-shader.frag'
54 | }))
55 |
56 | function render() {
57 | post.bind()
58 |
59 | // Note that it's important you clear your
60 | // depth/color buffers for this to work properly :)
61 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
62 | gl.viewport(0, 0, canvas.width, canvas.height)
63 |
64 | // ...draw your scene to the framebuffer here...
65 |
66 | post.draw()
67 | }
68 | ```
69 |
70 | ### `post.shader`
71 |
72 | The shader you gave `gl-post` will also be exposed here, for quickly changing
73 | uniform variable values.
74 |
75 | ### `post.bind()`
76 |
77 | Starts drawing to the post-processing buffer. Anything you do now will not be
78 | immediately drawn to the screen, but instead drawn to an off-screen
79 | [framebuffer](http://github.com/stackgl/gl-fbo) for you to draw later using
80 | the post-processing shader.
81 |
82 | You should this when you're ready to start drawing your scene.
83 |
84 | ### `post.draw()`
85 |
86 | Draws the framebuffer to the screen using your shader, returning your drawing
87 | power to the screen in the process.
88 |
89 | ### `post.unbind()`
90 |
91 | Call this if you want to explicitly disable rendering to the framebuffer before
92 | drawing to the screen.
93 |
94 | ## License
95 |
96 | MIT. See [LICENSE.md](http://github.com/stackgl/gl-post/blob/master/LICENSE.md) for details.
97 |
--------------------------------------------------------------------------------