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