Skip to content

Commit 22a4c76

Browse files
spidersharma03mrdoob
authored andcommitted
Bloom Pass - Inspired from Unreal Engine (mrdoob#9351)
* Bloom Pass Inspired from Unreal * Extract Bright Pass * Mip Map blur Pass * Combine Pass * resize function in Bloom resize function in Bloom * Bug Fixes and a few Changes * Resize bug fix * changed blur filter. Need to reinvestigate, the older blur sometime * Changed kernel size. was too big.
1 parent a93fd5f commit 22a4c76

File tree

5 files changed

+675
-0
lines changed

5 files changed

+675
-0
lines changed

examples/files.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ var files = {
205205
"webgl_postprocessing_smaa",
206206
"webgl_postprocessing_ssao",
207207
"webgl_postprocessing_taa",
208+
"webgl_postprocessing_unreal_bloom",
208209
"webgl_raycast_texture",
209210
"webgl_read_float_buffer",
210211
"webgl_rtt",
Lines changed: 329 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,329 @@
1+
/**
2+
* @author spidersharma / http://eduperiment.com/
3+
Inspired from Unreal Engine::
4+
https://docs.unrealengine.com/latest/INT/Engine/Rendering/PostProcessEffects/Bloom/
5+
*/
6+
7+
THREE.UnrealBloomPass = function ( resolution, strength, radius, threshold ) {
8+
9+
THREE.Pass.call( this );
10+
11+
this.strength = ( strength !== undefined ) ? strength : 1;
12+
this.radius = radius;
13+
this.threshold = threshold;
14+
this.resolution = ( resolution !== undefined ) ? new THREE.Vector2(resolution.x, resolution.y) : new THREE.Vector2(256, 256);
15+
16+
// render targets
17+
var pars = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat };
18+
this.renderTargetsHorizontal = [];
19+
this.renderTargetsVertical = [];
20+
this.nMips = 5;
21+
var resx = Math.round(this.resolution.x/2);
22+
var resy = Math.round(this.resolution.y/2);
23+
24+
this.renderTargetBright = new THREE.WebGLRenderTarget( resx, resy, pars );
25+
this.renderTargetBright.texture.generateMipmaps = false;
26+
27+
for( var i=0; i<this.nMips; i++) {
28+
29+
var renderTarget = new THREE.WebGLRenderTarget( resx, resy, pars );
30+
31+
renderTarget.texture.generateMipmaps = false;
32+
33+
this.renderTargetsHorizontal.push(renderTarget);
34+
35+
var renderTarget = new THREE.WebGLRenderTarget( resx, resy, pars );
36+
37+
renderTarget.texture.generateMipmaps = false;
38+
39+
this.renderTargetsVertical.push(renderTarget);
40+
41+
resx = Math.round(resx/2);
42+
43+
resy = Math.round(resy/2);
44+
}
45+
46+
// luminosity high pass material
47+
48+
if ( THREE.LuminosityHighPassShader === undefined )
49+
console.error( "THREE.UnrealBloomPass relies on THREE.LuminosityHighPassShader" );
50+
51+
var highPassShader = THREE.LuminosityHighPassShader;
52+
this.highPassUniforms = THREE.UniformsUtils.clone( highPassShader.uniforms );
53+
54+
this.highPassUniforms[ "luminosityThreshold" ].value = threshold;
55+
this.highPassUniforms[ "smoothWidth" ].value = 0.01;
56+
57+
this.materialHighPassFilter = new THREE.ShaderMaterial( {
58+
uniforms: this.highPassUniforms,
59+
vertexShader: highPassShader.vertexShader,
60+
fragmentShader: highPassShader.fragmentShader,
61+
defines: {}
62+
} );
63+
64+
// Gaussian Blur Materials
65+
this.separableBlurMaterials = [];
66+
var kernelSizeArray = [3, 5, 7, 9, 11];
67+
var resx = Math.round(this.resolution.x/2);
68+
var resy = Math.round(this.resolution.y/2);
69+
70+
for( var i=0; i<this.nMips; i++) {
71+
72+
this.separableBlurMaterials.push(this.getSeperableBlurMaterial(kernelSizeArray[i]));
73+
74+
this.separableBlurMaterials[i].uniforms[ "texSize" ].value = new THREE.Vector2(resx, resy);
75+
76+
resx = Math.round(resx/2);
77+
78+
resy = Math.round(resy/2);
79+
}
80+
81+
// Composite material
82+
this.compositeMaterial = this.getCompositeMaterial(this.nMips);
83+
this.compositeMaterial.uniforms["blurTexture1"].value = this.renderTargetsVertical[0].texture;
84+
this.compositeMaterial.uniforms["blurTexture2"].value = this.renderTargetsVertical[1].texture;
85+
this.compositeMaterial.uniforms["blurTexture3"].value = this.renderTargetsVertical[2].texture;
86+
this.compositeMaterial.uniforms["blurTexture4"].value = this.renderTargetsVertical[3].texture;
87+
this.compositeMaterial.uniforms["blurTexture5"].value = this.renderTargetsVertical[4].texture;
88+
this.compositeMaterial.uniforms["bloomStrength"].value = strength;
89+
this.compositeMaterial.uniforms["bloomRadius"].value = 0.1;
90+
this.compositeMaterial.needsUpdate = true;
91+
92+
var bloomFactors = [1.0, 0.8, 0.6, 0.4, 0.2];
93+
this.compositeMaterial.uniforms["bloomFactors"].value = bloomFactors;
94+
this.bloomTintColors = [new THREE.Vector3(1,1,1), new THREE.Vector3(1,1,1), new THREE.Vector3(1,1,1)
95+
,new THREE.Vector3(1,1,1), new THREE.Vector3(1,1,1)];
96+
this.compositeMaterial.uniforms["bloomTintColors"].value = this.bloomTintColors;
97+
98+
// copy material
99+
if ( THREE.CopyShader === undefined )
100+
console.error( "THREE.BloomPass relies on THREE.CopyShader" );
101+
102+
var copyShader = THREE.CopyShader;
103+
104+
this.copyUniforms = THREE.UniformsUtils.clone( copyShader.uniforms );
105+
this.copyUniforms[ "opacity" ].value = 1.0;
106+
107+
this.materialCopy = new THREE.ShaderMaterial( {
108+
uniforms: this.copyUniforms,
109+
vertexShader: copyShader.vertexShader,
110+
fragmentShader: copyShader.fragmentShader,
111+
blending: THREE.AdditiveBlending,
112+
depthTest: false,
113+
depthWrite: false,
114+
transparent: true
115+
} );
116+
117+
this.enabled = true;
118+
this.needsSwap = false;
119+
120+
this.oldClearColor = new THREE.Color();
121+
this.oldClearAlpha = 1;
122+
123+
this.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
124+
this.scene = new THREE.Scene();
125+
126+
this.quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null );
127+
this.scene.add( this.quad );
128+
129+
};
130+
131+
THREE.UnrealBloomPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
132+
133+
constructor: THREE.UnrealBloomPass,
134+
135+
dispose: function() {
136+
for( var i=0; i< this.renderTargetsHorizontal.length(); i++) {
137+
this.renderTargetsHorizontal[i].dispose();
138+
}
139+
for( var i=0; i< this.renderTargetsVertical.length(); i++) {
140+
this.renderTargetsVertical[i].dispose();
141+
}
142+
this.renderTargetBright.dispose();
143+
},
144+
145+
setSize: function ( width, height ) {
146+
147+
var resx = Math.round(width/2);
148+
var resy = Math.round(height/2);
149+
150+
this.renderTargetBright.setSize(resx, resy);
151+
152+
for( var i=0; i<this.nMips; i++) {
153+
154+
this.renderTargetsHorizontal[i].setSize(resx, resy);
155+
this.renderTargetsVertical[i].setSize(resx, resy);
156+
157+
this.separableBlurMaterials[i].uniforms[ "texSize" ].value = new THREE.Vector2(resx, resy);
158+
159+
resx = Math.round(resx/2);
160+
resy = Math.round(resy/2);
161+
}
162+
},
163+
164+
render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
165+
166+
this.oldClearColor.copy( renderer.getClearColor() );
167+
this.oldClearAlpha = renderer.getClearAlpha();
168+
var oldAutoClear = renderer.autoClear;
169+
renderer.autoClear = false;
170+
171+
renderer.setClearColor( new THREE.Color( 0, 0, 0 ), 0 );
172+
173+
if ( maskActive ) renderer.context.disable( renderer.context.STENCIL_TEST );
174+
175+
// 1. Extract Bright Areas
176+
this.highPassUniforms[ "tDiffuse" ].value = readBuffer.texture;
177+
this.highPassUniforms[ "luminosityThreshold" ].value = this.threshold;
178+
this.quad.material = this.materialHighPassFilter;
179+
renderer.render( this.scene, this.camera, this.renderTargetBright, true );
180+
181+
// 2. Blur All the mips progressively
182+
var inputRenderTarget = this.renderTargetBright;
183+
184+
for(var i=0; i<this.nMips; i++) {
185+
186+
this.quad.material = this.separableBlurMaterials[i];
187+
188+
this.separableBlurMaterials[i].uniforms[ "colorTexture" ].value = inputRenderTarget.texture;
189+
190+
this.separableBlurMaterials[i].uniforms[ "direction" ].value = THREE.UnrealBloomPass.BlurDirectionX;
191+
192+
renderer.render( this.scene, this.camera, this.renderTargetsHorizontal[i], true );
193+
194+
this.separableBlurMaterials[i].uniforms[ "colorTexture" ].value = this.renderTargetsHorizontal[i].texture;
195+
196+
this.separableBlurMaterials[i].uniforms[ "direction" ].value = THREE.UnrealBloomPass.BlurDirectionY;
197+
198+
renderer.render( this.scene, this.camera, this.renderTargetsVertical[i], true );
199+
200+
inputRenderTarget = this.renderTargetsVertical[i];
201+
}
202+
203+
// Composite All the mips
204+
this.quad.material = this.compositeMaterial;
205+
this.compositeMaterial.uniforms["bloomStrength"].value = this.strength;
206+
this.compositeMaterial.uniforms["bloomRadius"].value = this.radius;
207+
this.compositeMaterial.uniforms["bloomTintColors"].value = this.bloomTintColors;
208+
renderer.render( this.scene, this.camera, this.renderTargetsHorizontal[0], true );
209+
210+
// Blend it additively over the input texture
211+
this.quad.material = this.materialCopy;
212+
this.copyUniforms[ "tDiffuse" ].value = this.renderTargetsHorizontal[0].texture;
213+
214+
if ( maskActive ) renderer.context.enable( renderer.context.STENCIL_TEST );
215+
216+
renderer.render( this.scene, this.camera, readBuffer, false );
217+
218+
renderer.setClearColor( this.oldClearColor, this.oldClearAlpha );
219+
renderer.autoClear = oldAutoClear;
220+
},
221+
222+
getSeperableBlurMaterial: function(kernelRadius) {
223+
224+
return new THREE.ShaderMaterial( {
225+
226+
defines: {
227+
"KERNEL_RADIUS" : kernelRadius,
228+
"SIGMA" : kernelRadius
229+
},
230+
231+
uniforms: {
232+
"colorTexture": { value: null },
233+
"texSize": { value: new THREE.Vector2( 0.5, 0.5 ) },
234+
"direction": { value: new THREE.Vector2( 0.5, 0.5 ) },
235+
},
236+
237+
vertexShader:
238+
"varying vec2 vUv;\n\
239+
void main() {\n\
240+
vUv = uv;\n\
241+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\
242+
}",
243+
244+
fragmentShader:
245+
"#include <common>\
246+
varying vec2 vUv;\n\
247+
uniform sampler2D colorTexture;\n\
248+
uniform vec2 texSize;\
249+
uniform vec2 direction;\
250+
\
251+
void main() {\n\
252+
vec2 invSize = 1.0 / texSize;\
253+
float fSigma = float(SIGMA);\
254+
float weightSum = gaussianPdf(0.0, fSigma);\
255+
vec3 diffuseSum = texture2D( colorTexture, vUv).rgb * weightSum;\
256+
for( int i = 1; i < KERNEL_RADIUS; i ++ ) {\
257+
float x = float(i);\
258+
float w = gaussianPdf(x, fSigma);\
259+
vec2 uvOffset = direction * invSize * x;\
260+
vec3 sample1 = texture2D( colorTexture, vUv + uvOffset).rgb;\
261+
vec3 sample2 = texture2D( colorTexture, vUv - uvOffset).rgb;\
262+
diffuseSum += (sample1 + sample2) * w;\
263+
weightSum += 2.0 * w;\
264+
}\
265+
gl_FragColor = vec4(diffuseSum/weightSum, 1.0);\n\
266+
}"
267+
} );
268+
},
269+
270+
getCompositeMaterial: function(nMips) {
271+
272+
return new THREE.ShaderMaterial( {
273+
274+
defines:{
275+
"NUM_MIPS" : nMips
276+
},
277+
278+
uniforms: {
279+
"blurTexture1": { value: null },
280+
"blurTexture2": { value: null },
281+
"blurTexture3": { value: null },
282+
"blurTexture4": { value: null },
283+
"blurTexture5": { value: null },
284+
"dirtTexture": { value: null },
285+
"bloomStrength" : { value: 1.0 },
286+
"bloomFactors" : { value: null },
287+
"bloomTintColors" : { value: null },
288+
"bloomRadius" : { value: 0.0 }
289+
},
290+
291+
vertexShader:
292+
"varying vec2 vUv;\n\
293+
void main() {\n\
294+
vUv = uv;\n\
295+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\
296+
}",
297+
298+
fragmentShader:
299+
"varying vec2 vUv;\
300+
uniform sampler2D blurTexture1;\
301+
uniform sampler2D blurTexture2;\
302+
uniform sampler2D blurTexture3;\
303+
uniform sampler2D blurTexture4;\
304+
uniform sampler2D blurTexture5;\
305+
uniform sampler2D dirtTexture;\
306+
uniform float bloomStrength;\
307+
uniform float bloomRadius;\
308+
uniform float bloomFactors[NUM_MIPS];\
309+
uniform vec3 bloomTintColors[NUM_MIPS];\
310+
\
311+
float lerpBloomFactor(const in float factor) { \
312+
float mirrorFactor = 1.2 - factor;\
313+
return mix(factor, mirrorFactor, bloomRadius);\
314+
}\
315+
\
316+
void main() {\
317+
gl_FragColor = bloomStrength * ( lerpBloomFactor(bloomFactors[0]) * vec4(bloomTintColors[0], 1.0) * texture2D(blurTexture1, vUv) + \
318+
lerpBloomFactor(bloomFactors[1]) * vec4(bloomTintColors[1], 1.0) * texture2D(blurTexture2, vUv) + \
319+
lerpBloomFactor(bloomFactors[2]) * vec4(bloomTintColors[2], 1.0) * texture2D(blurTexture3, vUv) + \
320+
lerpBloomFactor(bloomFactors[3]) * vec4(bloomTintColors[3], 1.0) * texture2D(blurTexture4, vUv) + \
321+
lerpBloomFactor(bloomFactors[4]) * vec4(bloomTintColors[4], 1.0) * texture2D(blurTexture5, vUv) );\
322+
}"
323+
} );
324+
}
325+
326+
} );
327+
328+
THREE.UnrealBloomPass.BlurDirectionX = new THREE.Vector2( 1.0, 0.0 );
329+
THREE.UnrealBloomPass.BlurDirectionY = new THREE.Vector2( 0.0, 1.0 );

0 commit comments

Comments
 (0)