├── .gitignore ├── README.md ├── deferred-rendering.jpg ├── fx ├── Contrast.glsl ├── Contrast.js ├── SSAO.glsl └── SSAO.js ├── index.html ├── lib └── watchscript.js ├── main.js ├── materials ├── DeferredPointLight.glsl └── DeferredPointLight.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | stuff 3 | .DS_Store 4 | main.web.js -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |  2 | 3 | Deferred rendering with sphere clipped lights in WebGL developed in [pex](http://github.com/vorg/pex/). -------------------------------------------------------------------------------- /deferred-rendering.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pex-exp-deferred-rendering/1f2ffd6a30199bff60691220851760a9bd5cf068/deferred-rendering.jpg -------------------------------------------------------------------------------- /fx/Contrast.glsl: -------------------------------------------------------------------------------- 1 | #ifdef VERT 2 | 3 | attribute vec2 position; 4 | attribute vec2 texCoord; 5 | varying vec2 vTexCoord; 6 | 7 | void main() { 8 | gl_Position = vec4(position, 0.0, 1.0); 9 | vTexCoord = texCoord; 10 | } 11 | 12 | #endif 13 | 14 | #ifdef FRAG 15 | 16 | varying vec2 vTexCoord; 17 | uniform sampler2D tex0; 18 | uniform float contrast; 19 | 20 | void main() { 21 | vec4 color = texture2D(tex0, vTexCoord).rgba; 22 | gl_FragColor.rgb = (color.rgb - 0.5) * contrast + 0.5; 23 | gl_FragColor.a = color.a; 24 | } 25 | 26 | #endif -------------------------------------------------------------------------------- /fx/Contrast.js: -------------------------------------------------------------------------------- 1 | var fx = require('pex-fx'); 2 | var FXStage = fx.FXStage; 3 | var fs = require('fs'); 4 | 5 | var ContrastGLSL = fs.readFileSync(__dirname + '/Contrast.glsl', 'utf8'); 6 | 7 | FXStage.prototype.contrast = function (options) { 8 | options = options || { contrast: 1 }; 9 | var outputSize = this.getOutputSize(options.width, options.height); 10 | var rt = this.getRenderTarget(outputSize.width, outputSize.height, options.depth, options.bpp); 11 | rt.bind(); 12 | this.getSourceTexture().bind(0); 13 | var program = this.getShader(ContrastGLSL); 14 | program.use(); 15 | program.uniforms.tex0(0); 16 | program.uniforms.contrast(options.contrast); 17 | this.drawFullScreenQuad(outputSize.width, outputSize.height, null, program); 18 | rt.unbind(); 19 | return this.asFXStage(rt, 'contrast'); 20 | }; 21 | 22 | module.exports = FXStage; -------------------------------------------------------------------------------- /fx/SSAO.glsl: -------------------------------------------------------------------------------- 1 | //based on http://blenderartists.org/forum/showthread.php?184102-nicer-and-faster-SSAO and http://www.pasteall.org/12299 2 | #ifdef VERT 3 | 4 | attribute vec2 position; 5 | attribute vec2 texCoord; 6 | 7 | varying vec2 vTexCoord; 8 | 9 | void main() { 10 | gl_Position = vec4(position, 0.0, 1.0); 11 | vTexCoord = texCoord; 12 | } 13 | 14 | #endif 15 | 16 | #ifdef FRAG 17 | 18 | #define PI 3.14159265 19 | 20 | varying vec2 vTexCoord; 21 | 22 | uniform sampler2D depthMap; 23 | uniform vec2 textureSize; 24 | uniform float near; 25 | uniform float far; 26 | 27 | const int samples = 3; 28 | const int rings = 5; 29 | 30 | uniform float strength; 31 | uniform float cutoutBg; 32 | 33 | vec2 rand(vec2 coord) { 34 | float noiseX = (fract(sin(dot(coord, vec2(12.9898,78.233))) * 43758.5453)); 35 | float noiseY = (fract(sin(dot(coord, vec2(12.9898,78.233) * 2.0)) * 43758.5453)); 36 | return vec2(noiseX,noiseY) * 0.004; 37 | } 38 | 39 | float compareDepths( in float depth1, in float depth2 ) 40 | { 41 | float aoCap = 1.0; 42 | float aoMultiplier = 100.0; 43 | float depthTolerance = 0.003; 44 | float aorange = 5.0;// units in space the AO effect extends to (this gets divided by the camera far range 45 | float diff = sqrt(clamp(1.0-(depth1-depth2) / (aorange/(far-near)),0.0,1.0)); 46 | float ao = min(aoCap, max(0.0, depth1-depth2-depthTolerance) * aoMultiplier) * diff; 47 | //if (diff > depthTolerance * 500) return 0; 48 | return ao * strength; 49 | } 50 | 51 | float readDepth(vec2 coord) { 52 | return texture2D(depthMap, coord).a/far; 53 | } 54 | 55 | void main() { 56 | vec2 texCoord = vec2(gl_FragCoord.x / textureSize.x, gl_FragCoord.y / textureSize.y); 57 | float depth = readDepth(texCoord); 58 | 59 | float d; 60 | 61 | float aspect = textureSize.x / textureSize.y; 62 | vec2 noise = rand(vTexCoord); 63 | 64 | float w = (1.0 / textureSize.x)/clamp(depth,0.05,1.0)+(noise.x*(1.0-noise.x)); 65 | float h = (1.0 / textureSize.y)/clamp(depth,0.05,1.0)+(noise.y*(1.0-noise.y)); 66 | 67 | float pw; 68 | float ph; 69 | 70 | float ao = 0.0; 71 | float s = 0.0; 72 | float fade = 4.0; 73 | 74 | for (int i = 0 ; i < rings; i += 1) 75 | { 76 | fade *= 0.5; 77 | for (int j = 0 ; j < samples*rings; j += 1) 78 | { 79 | if (j >= samples*i) break; 80 | float step = PI * 2.0 / (float(samples) * float(i)); 81 | pw = (cos(float(j)*step) * float(i) * 0.5); 82 | ph = (sin(float(j)*step) * float(i) * 0.5) * aspect; 83 | d = readDepth( vec2(texCoord.s + pw * w,texCoord.t + ph * h)); 84 | ao += compareDepths(depth, d) * fade; 85 | s += 1.0 * fade; 86 | } 87 | } 88 | 89 | ao /= s; 90 | ao *= 1.5; 91 | ao = 1.0 - ao; 92 | 93 | if (depth > 0.99) ao += 0.5; 94 | 95 | vec3 black = vec3(0.0, 0.0, 0.0); 96 | vec3 treshold = vec3(0.2, 0.2, 0.2); 97 | 98 | gl_FragColor = vec4(texCoord, 0.0, 1.0); 99 | //gl_FragColor = vec4(getDepth(texCoord), 0.0, 0.0, 1.0); 100 | gl_FragColor = vec4(ao, ao, ao, 1.0); 101 | 102 | if (depth*cutoutBg > 0.5) gl_FragColor = vec4(0.0); 103 | } 104 | 105 | #endif -------------------------------------------------------------------------------- /fx/SSAO.js: -------------------------------------------------------------------------------- 1 | var fx = require('pex-fx'); 2 | var FXStage = fx.FXStage; 3 | var geom = require('pex-geom') 4 | var Vec2 = geom.Vec2; 5 | var fs = require('fs'); 6 | 7 | var SSAOGLSL = fs.readFileSync(__dirname + '/SSAO.glsl', 'utf8'); 8 | 9 | FXStage.prototype.ssao = function (options) { 10 | options = options || {}; 11 | var outputSize = this.getOutputSize(options.width, options.height); 12 | var rt = this.getRenderTarget(outputSize.width, outputSize.height, options.depth, options.bpp); 13 | rt.bind(); 14 | var depthMap = this.getSourceTexture(options.depthMap); 15 | depthMap.bind(0); 16 | var program = this.getShader(SSAOGLSL); 17 | program.use(); 18 | program.uniforms.textureSize(Vec2.create(depthMap.width, depthMap.height)); 19 | program.uniforms.depthMap(0); 20 | program.uniforms.near(options.camera.getNear()); 21 | program.uniforms.far(options.camera.getFar()); 22 | program.uniforms.strength(options.strength === null ? 1 : options.strength); 23 | program.uniforms.cutoutBg(options.cutoutBg ? 1 : 0); 24 | this.drawFullScreenQuad(outputSize.width, outputSize.height, null, program); 25 | rt.unbind(); 26 | return this.asFXStage(rt, 'ssao'); 27 | }; 28 | 29 | module.exports = FXStage; -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 |