Skip to content

Commit 502b059

Browse files
authored
Merge pull request #18 from davepagurek/gaussian
Add Gaussian blur renderer
2 parents 76f50c0 + 00a4403 commit 502b059

File tree

6 files changed

+256
-3
lines changed

6 files changed

+256
-3
lines changed

GaussianBlurRenderer.js

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
class GaussianBlurRenderer extends BlurRenderer {
2+
constructor(target) {
3+
super(target)
4+
this.fbo2 = target.createFramebuffer()
5+
this.intensity = 0.1
6+
this.numSamples = 20
7+
}
8+
9+
frag() {
10+
return GaussianBlurRenderer.frag
11+
}
12+
13+
getUniforms() {
14+
const uniforms = super.getUniforms()
15+
delete uniforms.uImg
16+
return uniforms
17+
}
18+
19+
draw(cb) {
20+
const prevCamera = this.target._renderer._curCamera
21+
this.fbo.draw(() => {
22+
this.target.push()
23+
cb()
24+
this.target.pop()
25+
})
26+
27+
const uniforms = this.getUniforms()
28+
29+
this.target.push()
30+
this.target.setCamera(this.cam)
31+
this.cam.move(0, 0, 0)
32+
33+
this.fbo2.draw(() => {
34+
this.target.push()
35+
this.target.noStroke()
36+
this.target.rectMode(CENTER)
37+
this.target.shader(this.shader)
38+
for (const key in uniforms) {
39+
this.shader.setUniform(key, uniforms[key])
40+
this.shader.setUniform('uDirection', 0)
41+
this.shader.setUniform('uImg', this.fbo.color)
42+
}
43+
this.target.rect(0, 0, this.target.width, -this.target.height)
44+
this.target.pop()
45+
})
46+
47+
this.target.noStroke()
48+
this.target.rectMode(CENTER)
49+
this.target.shader(this.shader)
50+
for (const key in uniforms) {
51+
this.shader.setUniform(key, uniforms[key])
52+
}
53+
this.shader.setUniform('uDirection', 1)
54+
this.shader.setUniform('uImg', this.fbo2.color)
55+
this.target.rect(0, 0, this.target.width, -this.target.height)
56+
this.target.pop()
57+
this.target.setCamera(prevCamera)
58+
}
59+
60+
remove() {
61+
super.remove()
62+
this.fbo2.remove()
63+
}
64+
}
65+
66+
p5.prototype.createGaussianBlurRenderer = function() {
67+
return new GaussianBlurRenderer(this)
68+
}
69+
70+
GaussianBlurRenderer.frag = `
71+
precision highp float;
72+
varying highp vec2 vVertTexCoord;
73+
uniform sampler2D uImg;
74+
uniform sampler2D uDepth;
75+
uniform vec2 uSize;
76+
uniform float uIntensity;
77+
uniform float uDof;
78+
uniform float maxBlur;
79+
uniform int uNumSamples;
80+
uniform float uTargetZ;
81+
uniform float uNear;
82+
uniform float uFar;
83+
uniform int uDirection;
84+
#define s ${0.5/3}
85+
const int MAX_NUM_SAMPLES = 50;
86+
float depthToZ(float depth) {
87+
float depthNormalized = 2.0 * depth - 1.0;
88+
return 2.0 * uNear * uFar / (uFar + uNear - depthNormalized * (uFar - uNear));
89+
}
90+
float calcBlur(float z, float pixelScale) {
91+
return clamp(abs(z - uTargetZ) - uDof / 2., 0.0, 0.3*pixelScale);
92+
}
93+
void main() {
94+
float total = 1.0;
95+
float origZ = depthToZ(texture2D(uDepth, vVertTexCoord).x);
96+
vec4 color = texture2D(uImg, vVertTexCoord);
97+
if (abs(origZ - uTargetZ) > uDof / 2.) {
98+
float pixelScale = max(uSize.x, uSize.y);
99+
float blurAmt = calcBlur(origZ, pixelScale);
100+
for (int i = 0; i < MAX_NUM_SAMPLES; i++) {
101+
if (i >= uNumSamples) break;
102+
float t = (float(i) / float(uNumSamples - 1));
103+
float radius = (t * 2. - 1.);
104+
float distAway = radius * uIntensity * blurAmt;
105+
vec2 offset = (uDirection == 0 ? vec2(1.,0.) : vec2(0.,1.)) * distAway / pixelScale;
106+
float z = depthToZ(texture2D(uDepth, vVertTexCoord + offset).x);
107+
float sampleBlur = calcBlur(z, pixelScale);
108+
float t2 = distAway / (sampleBlur * uIntensity);
109+
float weight = ${1/Math.sqrt(2*Math.PI)} / s * exp(-0.5*pow(t2/s,2.));
110+
vec4 sample = texture2D(uImg, vVertTexCoord + offset);
111+
color += weight * sample;
112+
total += weight;
113+
}
114+
}
115+
color /= total;
116+
gl_FragColor = color;
117+
}
118+
`

README.md

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Add the library to your source code, *after* loading p5 but *before* loading you
1818

1919
### Via CDN
2020
```html
21-
<script src="https://cdn.jsdelivr.net/npm/@davepagurek/[email protected].5/p5.Framebuffer.min.js"></script>
21+
<script src="https://cdn.jsdelivr.net/npm/@davepagurek/[email protected].6/p5.Framebuffer.min.js"></script>
2222
```
2323

2424
### Self-hosted
@@ -197,6 +197,81 @@ The library provides a helper that bundles a Framebuffer with a shader that appl
197197

198198
Create a blur renderer and draw inside its `draw` callback. When you tell it to `focusHere()`, anything drawn at that transformed position will be in focus. You can use standard p5 `translate` calls to position the focal point.
199199

200+
#### Gaussian blur
201+
202+
This is likely the best-looking blur renderer, although it uses two render passes. Start by using this one, but look out the other `BlurRenderer` if it's slow.
203+
204+
<table>
205+
<tr>
206+
<td>
207+
208+
```js
209+
let blurRenderer
210+
211+
function setup() {
212+
createCanvas(400, 400, WEBGL)
213+
blurRenderer = createGaussianBlurRenderer()
214+
blurRenderer.setIntensity(0.15)
215+
blurRenderer.setSamples(20)
216+
blurRenderer.setDof(50)
217+
}
218+
219+
function draw() {
220+
blurRenderer.draw(() => {
221+
clear()
222+
push()
223+
background(255)
224+
noStroke()
225+
lights()
226+
227+
push()
228+
fill('blue')
229+
translate(-80, -80, -300)
230+
blurRenderer.focusHere()
231+
sphere(50)
232+
pop()
233+
234+
push()
235+
fill('red')
236+
sphere(50)
237+
pop()
238+
pop()
239+
})
240+
}
241+
```
242+
243+
</td>
244+
<td>
245+
<img src="https://user-images.githubusercontent.com/5315059/201497333-92a3f46e-91b7-4d4e-a675-f958d8d9ff50.png" width="400" height="400">
246+
</td>
247+
</tr>
248+
</table>
249+
250+
Methods on `GaussianBlurRenderer`:
251+
- `GaussianBlurRenderer.prototype.draw(callback: () => void)`
252+
- Draw the scene defined in the callback with blur
253+
- `GaussianBlurRenderer.prototype.focusHere()`
254+
- Tell the renderer what point in space should be in focus. It will move based on any calls to `translate()` or other transformations that you have applied.
255+
- Defaults to the origin
256+
- `GaussianBlurRenderer.prototype.setIntensity(intensity: number)`
257+
- Control the intensity of the blur, between 0 and 1: the lower the intensity, the farther objects have to be from the focal point to be blurred
258+
- Defaults to 0.1
259+
- `GaussianBlurRenderer.prototype.setDof(dof: number)`
260+
- Control the depth of field (dof), which is the distance away from the focal point that is also in focus, from 0 up
261+
- The lower the dof, the smaller range will be that has no blur. Blur amount will start to accumulate when objects are outside of the dof range
262+
- The focal target (set by `focusHere`) is located in the centre of the clear range. So assume the focal target's depth value is `z`, then the clear range becomes from `z - dof / 2` to `z + dof / 2`.
263+
- Defaults to 0
264+
- `GaussianBlurRenderer.prototype.setSamples(numSamples: number)`
265+
- Control how many random samples to use in the blur shader. More samples will look smoother but is more computationally intensive.
266+
- Defaults to 20
267+
268+
A live example: https://davepagurek.github.io/p5.Framebuffer/examples/gaussianblur
269+
270+
271+
#### One-pass blur
272+
273+
Another implementation of blur, but using a single shader pass. This will likely produce a grainier result, but might be faster on some systems.
274+
200275
<table>
201276
<tr>
202277
<td>

examples/gaussianblur/index.html

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<!DOCTYPE html><html lang="en"><head>
2+
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.min.js"></script>
3+
<script src="../../p5.Framebuffer.js" type="text/javascript"></script>
4+
<script src="../../Renderer.js" type="text/javascript"></script>
5+
<script src="../../BlurRenderer.js" type="text/javascript"></script>
6+
<script src="../../GaussianBlurRenderer.js" type="text/javascript"></script>
7+
<link rel="stylesheet" type="text/css" href="style.css">
8+
<meta charset="utf-8">
9+
10+
</head>
11+
<body>
12+
<script src="sketch.js"></script>
13+
14+
15+
</body></html>

examples/gaussianblur/sketch.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
let blurRenderer
2+
3+
function setup() {
4+
createCanvas(400, 400, WEBGL)
5+
blurRenderer = createGaussianBlurRenderer()
6+
}
7+
8+
function draw() {
9+
blurRenderer.draw(() => {
10+
clear()
11+
push()
12+
background(255)
13+
noStroke()
14+
lights()
15+
16+
push()
17+
fill('red')
18+
translate(50*sin(millis()/500), 50*cos(millis()/500), 100*sin(millis()/800 + 100))
19+
sphere(50)
20+
pop()
21+
22+
push()
23+
fill('blue')
24+
translate(50*cos(millis()/300+12), 50*sin(millis()/600), 100*sin(millis()/800 + 1))
25+
sphere(50)
26+
blurRenderer.focusHere()
27+
pop()
28+
29+
push()
30+
fill('white')
31+
translate(0, 200, -100)
32+
rotateX(PI/2)
33+
plane(900, 900)
34+
pop()
35+
pop()
36+
})
37+
}

examples/gaussianblur/style.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
html, body {
2+
margin: 0;
3+
padding: 0;
4+
}
5+
canvas {
6+
display: block;
7+
}

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@davepagurek/p5.framebuffer",
3-
"version": "0.0.5",
3+
"version": "0.0.6",
44
"main": "p5.Framebuffer.js",
55
"author": "Dave Pagurek <[email protected]>",
66
"license": "MIT",
@@ -19,7 +19,7 @@
1919
},
2020
"scripts": {
2121
"build:core": "minify p5.Framebuffer.js > p5.Framebuffer.core.min.js",
22-
"build:all": "minify p5.Framebuffer.js > p5.Framebuffer.min.js; minify Renderer.js >> p5.Framebuffer.min.js; minify BlurRenderer.js >> p5.Framebuffer.min.js; minify ContactShadowRenderer.js >> p5.Framebuffer.min.js",
22+
"build:all": "minify p5.Framebuffer.js > p5.Framebuffer.min.js; minify Renderer.js >> p5.Framebuffer.min.js; minify BlurRenderer.js >> p5.Framebuffer.min.js; minify GaussianBlurRenderer.js >> p5.Framebuffer.min.js; minify ContactShadowRenderer.js >> p5.Framebuffer.min.js",
2323
"build": "yarn build:core && yarn build:all",
2424
"publish": "npm publish --access public"
2525
},
@@ -29,6 +29,7 @@
2929
"p5.Framebuffer.js",
3030
"Renderer.js",
3131
"BlurRenderer.js",
32+
"GaussianBlurRenderer.js",
3233
"ContactShadowRenderer.js"
3334
]
3435
}

0 commit comments

Comments
 (0)