SAOPass.js 13.8 KB
Newer Older
M
Marco Fugaro 已提交
1 2 3
( function () {

	/**
L
Ludovic Bailly 已提交
4 5 6
 * SAO implementation inspired from bhouston previous SAO work
 */

7 8
	class SAOPass extends THREE.Pass {

9
		constructor( scene, camera, useDepthTexture = false, useNormals = false, resolution = new THREE.Vector2( 256, 256 ) ) {
10 11 12 13 14 15

			super();
			this.scene = scene;
			this.camera = camera;
			this.clear = true;
			this.needsSwap = false;
16 17
			this.supportsDepthTextureExtension = useDepthTexture;
			this.supportsNormalTexture = useNormals;
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
			this.originalClearColor = new THREE.Color();
			this._oldClearColor = new THREE.Color();
			this.oldClearAlpha = 1;
			this.params = {
				output: 0,
				saoBias: 0.5,
				saoIntensity: 0.18,
				saoScale: 1,
				saoKernelRadius: 100,
				saoMinResolution: 0,
				saoBlur: true,
				saoBlurRadius: 8,
				saoBlurStdDev: 4,
				saoBlurDepthCutoff: 0.01
			};
33
			this.resolution = new THREE.Vector2( resolution.x, resolution.y );
34 35 36 37 38 39 40 41 42 43 44 45 46
			this.saoRenderTarget = new THREE.WebGLRenderTarget( this.resolution.x, this.resolution.y, {
				minFilter: THREE.LinearFilter,
				magFilter: THREE.LinearFilter,
				format: THREE.RGBAFormat
			} );
			this.blurIntermediateRenderTarget = this.saoRenderTarget.clone();
			this.beautyRenderTarget = this.saoRenderTarget.clone();
			this.normalRenderTarget = new THREE.WebGLRenderTarget( this.resolution.x, this.resolution.y, {
				minFilter: THREE.NearestFilter,
				magFilter: THREE.NearestFilter,
				format: THREE.RGBAFormat
			} );
			this.depthRenderTarget = this.normalRenderTarget.clone();
47
			let depthTexture;
48 49 50

			if ( this.supportsDepthTextureExtension ) {

51
				depthTexture = new THREE.DepthTexture();
52 53 54
				depthTexture.type = THREE.UnsignedShortType;
				this.beautyRenderTarget.depthTexture = depthTexture;
				this.beautyRenderTarget.depthBuffer = true;
L
Ludovic Bailly 已提交
55

56
			}
L
Ludovic Bailly 已提交
57

58 59 60 61 62
			this.depthMaterial = new THREE.MeshDepthMaterial();
			this.depthMaterial.depthPacking = THREE.RGBADepthPacking;
			this.depthMaterial.blending = THREE.NoBlending;
			this.normalMaterial = new THREE.MeshNormalMaterial();
			this.normalMaterial.blending = THREE.NoBlending;
L
Ludovic Bailly 已提交
63

64
			if ( THREE.SAOShader === undefined ) {
L
Ludovic Bailly 已提交
65

66
				console.error( 'THREE.SAOPass relies on THREE.SAOShader' );
L
Ludovic Bailly 已提交
67

68
			}
L
Ludovic Bailly 已提交
69

70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
			this.saoMaterial = new THREE.ShaderMaterial( {
				defines: Object.assign( {}, THREE.SAOShader.defines ),
				fragmentShader: THREE.SAOShader.fragmentShader,
				vertexShader: THREE.SAOShader.vertexShader,
				uniforms: THREE.UniformsUtils.clone( THREE.SAOShader.uniforms )
			} );
			this.saoMaterial.extensions.derivatives = true;
			this.saoMaterial.defines[ 'DEPTH_PACKING' ] = this.supportsDepthTextureExtension ? 0 : 1;
			this.saoMaterial.defines[ 'NORMAL_TEXTURE' ] = this.supportsNormalTexture ? 1 : 0;
			this.saoMaterial.defines[ 'PERSPECTIVE_CAMERA' ] = this.camera.isPerspectiveCamera ? 1 : 0;
			this.saoMaterial.uniforms[ 'tDepth' ].value = this.supportsDepthTextureExtension ? depthTexture : this.depthRenderTarget.texture;
			this.saoMaterial.uniforms[ 'tNormal' ].value = this.normalRenderTarget.texture;
			this.saoMaterial.uniforms[ 'size' ].value.set( this.resolution.x, this.resolution.y );
			this.saoMaterial.uniforms[ 'cameraInverseProjectionMatrix' ].value.copy( this.camera.projectionMatrixInverse );
			this.saoMaterial.uniforms[ 'cameraProjectionMatrix' ].value = this.camera.projectionMatrix;
			this.saoMaterial.blending = THREE.NoBlending;
L
Ludovic Bailly 已提交
86

87
			if ( THREE.DepthLimitedBlurShader === undefined ) {
L
Ludovic Bailly 已提交
88

89
				console.error( 'THREE.SAOPass relies on THREE.DepthLimitedBlurShader' );
L
Ludovic Bailly 已提交
90

91
			}
L
Ludovic Bailly 已提交
92

93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
			this.vBlurMaterial = new THREE.ShaderMaterial( {
				uniforms: THREE.UniformsUtils.clone( THREE.DepthLimitedBlurShader.uniforms ),
				defines: Object.assign( {}, THREE.DepthLimitedBlurShader.defines ),
				vertexShader: THREE.DepthLimitedBlurShader.vertexShader,
				fragmentShader: THREE.DepthLimitedBlurShader.fragmentShader
			} );
			this.vBlurMaterial.defines[ 'DEPTH_PACKING' ] = this.supportsDepthTextureExtension ? 0 : 1;
			this.vBlurMaterial.defines[ 'PERSPECTIVE_CAMERA' ] = this.camera.isPerspectiveCamera ? 1 : 0;
			this.vBlurMaterial.uniforms[ 'tDiffuse' ].value = this.saoRenderTarget.texture;
			this.vBlurMaterial.uniforms[ 'tDepth' ].value = this.supportsDepthTextureExtension ? depthTexture : this.depthRenderTarget.texture;
			this.vBlurMaterial.uniforms[ 'size' ].value.set( this.resolution.x, this.resolution.y );
			this.vBlurMaterial.blending = THREE.NoBlending;
			this.hBlurMaterial = new THREE.ShaderMaterial( {
				uniforms: THREE.UniformsUtils.clone( THREE.DepthLimitedBlurShader.uniforms ),
				defines: Object.assign( {}, THREE.DepthLimitedBlurShader.defines ),
				vertexShader: THREE.DepthLimitedBlurShader.vertexShader,
				fragmentShader: THREE.DepthLimitedBlurShader.fragmentShader
			} );
			this.hBlurMaterial.defines[ 'DEPTH_PACKING' ] = this.supportsDepthTextureExtension ? 0 : 1;
			this.hBlurMaterial.defines[ 'PERSPECTIVE_CAMERA' ] = this.camera.isPerspectiveCamera ? 1 : 0;
			this.hBlurMaterial.uniforms[ 'tDiffuse' ].value = this.blurIntermediateRenderTarget.texture;
			this.hBlurMaterial.uniforms[ 'tDepth' ].value = this.supportsDepthTextureExtension ? depthTexture : this.depthRenderTarget.texture;
			this.hBlurMaterial.uniforms[ 'size' ].value.set( this.resolution.x, this.resolution.y );
			this.hBlurMaterial.blending = THREE.NoBlending;

			if ( THREE.CopyShader === undefined ) {

				console.error( 'THREE.SAOPass relies on THREE.CopyShader' );
L
Ludovic Bailly 已提交
121

122
			}
L
Ludovic Bailly 已提交
123

124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
			this.materialCopy = new THREE.ShaderMaterial( {
				uniforms: THREE.UniformsUtils.clone( THREE.CopyShader.uniforms ),
				vertexShader: THREE.CopyShader.vertexShader,
				fragmentShader: THREE.CopyShader.fragmentShader,
				blending: THREE.NoBlending
			} );
			this.materialCopy.transparent = true;
			this.materialCopy.depthTest = false;
			this.materialCopy.depthWrite = false;
			this.materialCopy.blending = THREE.CustomBlending;
			this.materialCopy.blendSrc = THREE.DstColorFactor;
			this.materialCopy.blendDst = THREE.ZeroFactor;
			this.materialCopy.blendEquation = THREE.AddEquation;
			this.materialCopy.blendSrcAlpha = THREE.DstAlphaFactor;
			this.materialCopy.blendDstAlpha = THREE.ZeroFactor;
			this.materialCopy.blendEquationAlpha = THREE.AddEquation;

			if ( THREE.UnpackDepthRGBAShader === undefined ) {

				console.error( 'THREE.SAOPass relies on THREE.UnpackDepthRGBAShader' );
144

145
			}
L
Ludovic Bailly 已提交
146

147 148 149 150 151 152 153 154 155 156 157
			this.depthCopy = new THREE.ShaderMaterial( {
				uniforms: THREE.UniformsUtils.clone( THREE.UnpackDepthRGBAShader.uniforms ),
				vertexShader: THREE.UnpackDepthRGBAShader.vertexShader,
				fragmentShader: THREE.UnpackDepthRGBAShader.fragmentShader,
				blending: THREE.NoBlending
			} );
			this.fsQuad = new THREE.FullScreenQuad( null );

		}

		render( renderer, writeBuffer, readBuffer
M
Marco Fugaro 已提交
158 159
			/*, deltaTime, maskActive*/
		) {
L
Ludovic Bailly 已提交
160

M
Marco Fugaro 已提交
161 162
			// Rendering readBuffer first when rendering to screen
			if ( this.renderToScreen ) {
L
Ludovic Bailly 已提交
163

M
Marco Fugaro 已提交
164 165 166 167
				this.materialCopy.blending = THREE.NoBlending;
				this.materialCopy.uniforms[ 'tDiffuse' ].value = readBuffer.texture;
				this.materialCopy.needsUpdate = true;
				this.renderPass( renderer, this.materialCopy, null );
L
Ludovic Bailly 已提交
168

M
Marco Fugaro 已提交
169
			}
L
Ludovic Bailly 已提交
170

M
Marco Fugaro 已提交
171
			if ( this.params.output === 1 ) {
L
Ludovic Bailly 已提交
172

M
Marco Fugaro 已提交
173
				return;
L
Ludovic Bailly 已提交
174

M
Marco Fugaro 已提交
175
			}
L
Ludovic Bailly 已提交
176

M
Marco Fugaro 已提交
177 178
			renderer.getClearColor( this._oldClearColor );
			this.oldClearAlpha = renderer.getClearAlpha();
179
			const oldAutoClear = renderer.autoClear;
M
Marco Fugaro 已提交
180 181 182 183 184 185 186 187 188 189 190
			renderer.autoClear = false;
			renderer.setRenderTarget( this.depthRenderTarget );
			renderer.clear();
			this.saoMaterial.uniforms[ 'bias' ].value = this.params.saoBias;
			this.saoMaterial.uniforms[ 'intensity' ].value = this.params.saoIntensity;
			this.saoMaterial.uniforms[ 'scale' ].value = this.params.saoScale;
			this.saoMaterial.uniforms[ 'kernelRadius' ].value = this.params.saoKernelRadius;
			this.saoMaterial.uniforms[ 'minResolution' ].value = this.params.saoMinResolution;
			this.saoMaterial.uniforms[ 'cameraNear' ].value = this.camera.near;
			this.saoMaterial.uniforms[ 'cameraFar' ].value = this.camera.far; // this.saoMaterial.uniforms['randomSeed'].value = Math.random();

191
			const depthCutoff = this.params.saoBlurDepthCutoff * ( this.camera.far - this.camera.near );
M
Marco Fugaro 已提交
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
			this.vBlurMaterial.uniforms[ 'depthCutoff' ].value = depthCutoff;
			this.hBlurMaterial.uniforms[ 'depthCutoff' ].value = depthCutoff;
			this.vBlurMaterial.uniforms[ 'cameraNear' ].value = this.camera.near;
			this.vBlurMaterial.uniforms[ 'cameraFar' ].value = this.camera.far;
			this.hBlurMaterial.uniforms[ 'cameraNear' ].value = this.camera.near;
			this.hBlurMaterial.uniforms[ 'cameraFar' ].value = this.camera.far;
			this.params.saoBlurRadius = Math.floor( this.params.saoBlurRadius );

			if ( this.prevStdDev !== this.params.saoBlurStdDev || this.prevNumSamples !== this.params.saoBlurRadius ) {

				THREE.BlurShaderUtils.configure( this.vBlurMaterial, this.params.saoBlurRadius, this.params.saoBlurStdDev, new THREE.Vector2( 0, 1 ) );
				THREE.BlurShaderUtils.configure( this.hBlurMaterial, this.params.saoBlurRadius, this.params.saoBlurStdDev, new THREE.Vector2( 1, 0 ) );
				this.prevStdDev = this.params.saoBlurStdDev;
				this.prevNumSamples = this.params.saoBlurRadius;

			} // Rendering scene to depth texture


			renderer.setClearColor( 0x000000 );
			renderer.setRenderTarget( this.beautyRenderTarget );
			renderer.clear();
			renderer.render( this.scene, this.camera ); // Re-render scene if depth texture extension is not supported
L
Ludovic Bailly 已提交
214

M
Marco Fugaro 已提交
215
			if ( ! this.supportsDepthTextureExtension ) {
L
Ludovic Bailly 已提交
216

M
Marco Fugaro 已提交
217 218
				// Clear rule : far clipping plane in both RGBA and Basic encoding
				this.renderOverride( renderer, this.depthMaterial, this.depthRenderTarget, 0x000000, 1.0 );
L
Ludovic Bailly 已提交
219

M
Marco Fugaro 已提交
220
			}
L
Ludovic Bailly 已提交
221

M
Marco Fugaro 已提交
222
			if ( this.supportsNormalTexture ) {
L
Ludovic Bailly 已提交
223

M
Marco Fugaro 已提交
224 225
				// Clear rule : default normal is facing the camera
				this.renderOverride( renderer, this.normalMaterial, this.normalRenderTarget, 0x7777ff, 1.0 );
L
Ludovic Bailly 已提交
226

M
Marco Fugaro 已提交
227
			} // Rendering SAO texture
L
Ludovic Bailly 已提交
228 229


M
Marco Fugaro 已提交
230
			this.renderPass( renderer, this.saoMaterial, this.saoRenderTarget, 0xffffff, 1.0 ); // Blurring SAO texture
L
Ludovic Bailly 已提交
231

M
Marco Fugaro 已提交
232
			if ( this.params.saoBlur ) {
L
Ludovic Bailly 已提交
233

M
Marco Fugaro 已提交
234 235
				this.renderPass( renderer, this.vBlurMaterial, this.blurIntermediateRenderTarget, 0xffffff, 1.0 );
				this.renderPass( renderer, this.hBlurMaterial, this.saoRenderTarget, 0xffffff, 1.0 );
L
Ludovic Bailly 已提交
236 237 238

			}

239
			let outputMaterial = this.materialCopy; // Setting up SAO rendering
L
Ludovic Bailly 已提交
240

M
Marco Fugaro 已提交
241
			if ( this.params.output === 3 ) {
L
Ludovic Bailly 已提交
242

M
Marco Fugaro 已提交
243
				if ( this.supportsDepthTextureExtension ) {
L
Ludovic Bailly 已提交
244

M
Marco Fugaro 已提交
245 246
					this.materialCopy.uniforms[ 'tDiffuse' ].value = this.beautyRenderTarget.depthTexture;
					this.materialCopy.needsUpdate = true;
L
Ludovic Bailly 已提交
247

M
Marco Fugaro 已提交
248
				} else {
L
Ludovic Bailly 已提交
249

M
Marco Fugaro 已提交
250 251 252
					this.depthCopy.uniforms[ 'tDiffuse' ].value = this.depthRenderTarget.texture;
					this.depthCopy.needsUpdate = true;
					outputMaterial = this.depthCopy;
L
Ludovic Bailly 已提交
253

M
Marco Fugaro 已提交
254
				}
L
Ludovic Bailly 已提交
255

M
Marco Fugaro 已提交
256
			} else if ( this.params.output === 4 ) {
L
Ludovic Bailly 已提交
257

M
Marco Fugaro 已提交
258 259
				this.materialCopy.uniforms[ 'tDiffuse' ].value = this.normalRenderTarget.texture;
				this.materialCopy.needsUpdate = true;
L
Ludovic Bailly 已提交
260

M
Marco Fugaro 已提交
261
			} else {
L
Ludovic Bailly 已提交
262

M
Marco Fugaro 已提交
263 264
				this.materialCopy.uniforms[ 'tDiffuse' ].value = this.saoRenderTarget.texture;
				this.materialCopy.needsUpdate = true;
L
Ludovic Bailly 已提交
265

M
Marco Fugaro 已提交
266
			} // Blending depends on output, only want a THREE.CustomBlending when showing SAO
L
Ludovic Bailly 已提交
267 268


M
Marco Fugaro 已提交
269
			if ( this.params.output === 0 ) {
L
Ludovic Bailly 已提交
270

M
Marco Fugaro 已提交
271
				outputMaterial.blending = THREE.CustomBlending;
272

M
Marco Fugaro 已提交
273
			} else {
L
Ludovic Bailly 已提交
274

M
Marco Fugaro 已提交
275
				outputMaterial.blending = THREE.NoBlending;
L
Ludovic Bailly 已提交
276

M
Marco Fugaro 已提交
277
			} // Rendering SAOPass result on top of previous pass
L
Ludovic Bailly 已提交
278 279


M
Marco Fugaro 已提交
280 281 282
			this.renderPass( renderer, outputMaterial, this.renderToScreen ? null : readBuffer );
			renderer.setClearColor( this._oldClearColor, this.oldClearAlpha );
			renderer.autoClear = oldAutoClear;
L
Ludovic Bailly 已提交
283

284 285 286
		}

		renderPass( renderer, passMaterial, renderTarget, clearColor, clearAlpha ) {
L
Ludovic Bailly 已提交
287

M
Marco Fugaro 已提交
288 289
			// save original state
			renderer.getClearColor( this.originalClearColor );
290 291
			const originalClearAlpha = renderer.getClearAlpha();
			const originalAutoClear = renderer.autoClear;
M
Marco Fugaro 已提交
292
			renderer.setRenderTarget( renderTarget ); // setup pass state
L
Ludovic Bailly 已提交
293

M
Marco Fugaro 已提交
294
			renderer.autoClear = false;
L
Ludovic Bailly 已提交
295

M
Marco Fugaro 已提交
296
			if ( clearColor !== undefined && clearColor !== null ) {
L
Ludovic Bailly 已提交
297

M
Marco Fugaro 已提交
298 299 300
				renderer.setClearColor( clearColor );
				renderer.setClearAlpha( clearAlpha || 0.0 );
				renderer.clear();
L
Ludovic Bailly 已提交
301

M
Marco Fugaro 已提交
302
			}
L
Ludovic Bailly 已提交
303

M
Marco Fugaro 已提交
304 305
			this.fsQuad.material = passMaterial;
			this.fsQuad.render( renderer ); // restore original state
L
Ludovic Bailly 已提交
306

M
Marco Fugaro 已提交
307 308 309
			renderer.autoClear = originalAutoClear;
			renderer.setClearColor( this.originalClearColor );
			renderer.setClearAlpha( originalClearAlpha );
L
Ludovic Bailly 已提交
310

311 312 313
		}

		renderOverride( renderer, overrideMaterial, renderTarget, clearColor, clearAlpha ) {
L
Ludovic Bailly 已提交
314

M
Marco Fugaro 已提交
315
			renderer.getClearColor( this.originalClearColor );
316 317
			const originalClearAlpha = renderer.getClearAlpha();
			const originalAutoClear = renderer.autoClear;
M
Marco Fugaro 已提交
318 319 320 321
			renderer.setRenderTarget( renderTarget );
			renderer.autoClear = false;
			clearColor = overrideMaterial.clearColor || clearColor;
			clearAlpha = overrideMaterial.clearAlpha || clearAlpha;
L
Ludovic Bailly 已提交
322

M
Marco Fugaro 已提交
323
			if ( clearColor !== undefined && clearColor !== null ) {
L
Ludovic Bailly 已提交
324

M
Marco Fugaro 已提交
325 326 327
				renderer.setClearColor( clearColor );
				renderer.setClearAlpha( clearAlpha || 0.0 );
				renderer.clear();
L
Ludovic Bailly 已提交
328

M
Marco Fugaro 已提交
329
			}
L
Ludovic Bailly 已提交
330

M
Marco Fugaro 已提交
331 332 333 334 335 336 337 338
			this.scene.overrideMaterial = overrideMaterial;
			renderer.render( this.scene, this.camera );
			this.scene.overrideMaterial = null; // restore original state

			renderer.autoClear = originalAutoClear;
			renderer.setClearColor( this.originalClearColor );
			renderer.setClearAlpha( originalClearAlpha );

339 340 341
		}

		setSize( width, height ) {
M
Marco Fugaro 已提交
342 343 344 345 346 347 348 349 350 351 352 353 354 355

			this.beautyRenderTarget.setSize( width, height );
			this.saoRenderTarget.setSize( width, height );
			this.blurIntermediateRenderTarget.setSize( width, height );
			this.normalRenderTarget.setSize( width, height );
			this.depthRenderTarget.setSize( width, height );
			this.saoMaterial.uniforms[ 'size' ].value.set( width, height );
			this.saoMaterial.uniforms[ 'cameraInverseProjectionMatrix' ].value.copy( this.camera.projectionMatrixInverse );
			this.saoMaterial.uniforms[ 'cameraProjectionMatrix' ].value = this.camera.projectionMatrix;
			this.saoMaterial.needsUpdate = true;
			this.vBlurMaterial.uniforms[ 'size' ].value.set( width, height );
			this.vBlurMaterial.needsUpdate = true;
			this.hBlurMaterial.uniforms[ 'size' ].value.set( width, height );
			this.hBlurMaterial.needsUpdate = true;
L
Ludovic Bailly 已提交
356

M
Marco Fugaro 已提交
357
		}
358 359 360 361 362 363 364 365 366 367

	}

	SAOPass.OUTPUT = {
		'Beauty': 1,
		'Default': 0,
		'SAO': 2,
		'Depth': 3,
		'Normal': 4
	};
L
Ludovic Bailly 已提交
368

M
Marco Fugaro 已提交
369
	THREE.SAOPass = SAOPass;
L
Ludovic Bailly 已提交
370

M
Marco Fugaro 已提交
371
} )();