| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461 | import {	AddEquation,	Color,	CustomBlending,	DataTexture,	DepthTexture,	DstAlphaFactor,	DstColorFactor,	FloatType,	LinearFilter,	MathUtils,	MeshNormalMaterial,	NearestFilter,	NoBlending,	RGBAFormat,	RepeatWrapping,	ShaderMaterial,	UniformsUtils,	UnsignedShortType,	Vector3,	WebGLRenderTarget,	ZeroFactor} from '../../../build/three.module.js';import { Pass, FullScreenQuad } from './Pass.js';import { SimplexNoise } from '../math/SimplexNoise.js';import { SSAOShader } from '../shaders/SSAOShader.js';import { SSAOBlurShader } from '../shaders/SSAOShader.js';import { SSAODepthShader } from '../shaders/SSAOShader.js';import { CopyShader } from '../shaders/CopyShader.js';class SSAOPass extends Pass {	constructor( scene, camera, width, height ) {		super();		this.width = ( width !== undefined ) ? width : 512;		this.height = ( height !== undefined ) ? height : 512;		this.clear = true;		this.camera = camera;		this.scene = scene;		this.kernelRadius = 8;		this.kernelSize = 32;		this.kernel = [];		this.noiseTexture = null;		this.output = 0;		this.minDistance = 0.005;		this.maxDistance = 0.1;		this._visibilityCache = new Map();		//		this.generateSampleKernel();		this.generateRandomKernelRotations();		// beauty render target		const depthTexture = new DepthTexture();		depthTexture.type = UnsignedShortType;		this.beautyRenderTarget = new WebGLRenderTarget( this.width, this.height, {			minFilter: LinearFilter,			magFilter: LinearFilter,			format: RGBAFormat		} );		// normal render target with depth buffer		this.normalRenderTarget = new WebGLRenderTarget( this.width, this.height, {			minFilter: NearestFilter,			magFilter: NearestFilter,			format: RGBAFormat,			depthTexture: depthTexture		} );		// ssao render target		this.ssaoRenderTarget = new WebGLRenderTarget( this.width, this.height, {			minFilter: LinearFilter,			magFilter: LinearFilter,			format: RGBAFormat		} );		this.blurRenderTarget = this.ssaoRenderTarget.clone();		// ssao material		if ( SSAOShader === undefined ) {			console.error( 'THREE.SSAOPass: The pass relies on SSAOShader.' );		}		this.ssaoMaterial = new ShaderMaterial( {			defines: Object.assign( {}, SSAOShader.defines ),			uniforms: UniformsUtils.clone( SSAOShader.uniforms ),			vertexShader: SSAOShader.vertexShader,			fragmentShader: SSAOShader.fragmentShader,			blending: NoBlending		} );		this.ssaoMaterial.uniforms[ 'tDiffuse' ].value = this.beautyRenderTarget.texture;		this.ssaoMaterial.uniforms[ 'tNormal' ].value = this.normalRenderTarget.texture;		this.ssaoMaterial.uniforms[ 'tDepth' ].value = this.normalRenderTarget.depthTexture;		this.ssaoMaterial.uniforms[ 'tNoise' ].value = this.noiseTexture;		this.ssaoMaterial.uniforms[ 'kernel' ].value = this.kernel;		this.ssaoMaterial.uniforms[ 'cameraNear' ].value = this.camera.near;		this.ssaoMaterial.uniforms[ 'cameraFar' ].value = this.camera.far;		this.ssaoMaterial.uniforms[ 'resolution' ].value.set( this.width, this.height );		this.ssaoMaterial.uniforms[ 'cameraProjectionMatrix' ].value.copy( this.camera.projectionMatrix );		this.ssaoMaterial.uniforms[ 'cameraInverseProjectionMatrix' ].value.copy( this.camera.projectionMatrixInverse );		// normal material		this.normalMaterial = new MeshNormalMaterial();		this.normalMaterial.blending = NoBlending;		// blur material		this.blurMaterial = new ShaderMaterial( {			defines: Object.assign( {}, SSAOBlurShader.defines ),			uniforms: UniformsUtils.clone( SSAOBlurShader.uniforms ),			vertexShader: SSAOBlurShader.vertexShader,			fragmentShader: SSAOBlurShader.fragmentShader		} );		this.blurMaterial.uniforms[ 'tDiffuse' ].value = this.ssaoRenderTarget.texture;		this.blurMaterial.uniforms[ 'resolution' ].value.set( this.width, this.height );		// material for rendering the depth		this.depthRenderMaterial = new ShaderMaterial( {			defines: Object.assign( {}, SSAODepthShader.defines ),			uniforms: UniformsUtils.clone( SSAODepthShader.uniforms ),			vertexShader: SSAODepthShader.vertexShader,			fragmentShader: SSAODepthShader.fragmentShader,			blending: NoBlending		} );		this.depthRenderMaterial.uniforms[ 'tDepth' ].value = this.normalRenderTarget.depthTexture;		this.depthRenderMaterial.uniforms[ 'cameraNear' ].value = this.camera.near;		this.depthRenderMaterial.uniforms[ 'cameraFar' ].value = this.camera.far;		// material for rendering the content of a render target		this.copyMaterial = new ShaderMaterial( {			uniforms: UniformsUtils.clone( CopyShader.uniforms ),			vertexShader: CopyShader.vertexShader,			fragmentShader: CopyShader.fragmentShader,			transparent: true,			depthTest: false,			depthWrite: false,			blendSrc: DstColorFactor,			blendDst: ZeroFactor,			blendEquation: AddEquation,			blendSrcAlpha: DstAlphaFactor,			blendDstAlpha: ZeroFactor,			blendEquationAlpha: AddEquation		} );		this.fsQuad = new FullScreenQuad( null );		this.originalClearColor = new Color();	}	dispose() {		// dispose render targets		this.beautyRenderTarget.dispose();		this.normalRenderTarget.dispose();		this.ssaoRenderTarget.dispose();		this.blurRenderTarget.dispose();		// dispose materials		this.normalMaterial.dispose();		this.blurMaterial.dispose();		this.copyMaterial.dispose();		this.depthRenderMaterial.dispose();		// dipsose full screen quad		this.fsQuad.dispose();	}	render( renderer, writeBuffer /*, readBuffer, deltaTime, maskActive */ ) {		// render beauty		renderer.setRenderTarget( this.beautyRenderTarget );		renderer.clear();		renderer.render( this.scene, this.camera );		// render normals and depth (honor only meshes, points and lines do not contribute to SSAO)		this.overrideVisibility();		this.renderOverride( renderer, this.normalMaterial, this.normalRenderTarget, 0x7777ff, 1.0 );		this.restoreVisibility();		// render SSAO		this.ssaoMaterial.uniforms[ 'kernelRadius' ].value = this.kernelRadius;		this.ssaoMaterial.uniforms[ 'minDistance' ].value = this.minDistance;		this.ssaoMaterial.uniforms[ 'maxDistance' ].value = this.maxDistance;		this.renderPass( renderer, this.ssaoMaterial, this.ssaoRenderTarget );		// render blur		this.renderPass( renderer, this.blurMaterial, this.blurRenderTarget );		// output result to screen		switch ( this.output ) {			case SSAOPass.OUTPUT.SSAO:				this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.ssaoRenderTarget.texture;				this.copyMaterial.blending = NoBlending;				this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer );				break;			case SSAOPass.OUTPUT.Blur:				this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.blurRenderTarget.texture;				this.copyMaterial.blending = NoBlending;				this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer );				break;			case SSAOPass.OUTPUT.Beauty:				this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.beautyRenderTarget.texture;				this.copyMaterial.blending = NoBlending;				this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer );				break;			case SSAOPass.OUTPUT.Depth:				this.renderPass( renderer, this.depthRenderMaterial, this.renderToScreen ? null : writeBuffer );				break;			case SSAOPass.OUTPUT.Normal:				this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.normalRenderTarget.texture;				this.copyMaterial.blending = NoBlending;				this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer );				break;			case SSAOPass.OUTPUT.Default:				this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.beautyRenderTarget.texture;				this.copyMaterial.blending = NoBlending;				this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer );				this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.blurRenderTarget.texture;				this.copyMaterial.blending = CustomBlending;				this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer );				break;			default:				console.warn( 'THREE.SSAOPass: Unknown output type.' );		}	}	renderPass( renderer, passMaterial, renderTarget, clearColor, clearAlpha ) {		// save original state		renderer.getClearColor( this.originalClearColor );		const originalClearAlpha = renderer.getClearAlpha();		const originalAutoClear = renderer.autoClear;		renderer.setRenderTarget( renderTarget );		// setup pass state		renderer.autoClear = false;		if ( ( clearColor !== undefined ) && ( clearColor !== null ) ) {			renderer.setClearColor( clearColor );			renderer.setClearAlpha( clearAlpha || 0.0 );			renderer.clear();		}		this.fsQuad.material = passMaterial;		this.fsQuad.render( renderer );		// restore original state		renderer.autoClear = originalAutoClear;		renderer.setClearColor( this.originalClearColor );		renderer.setClearAlpha( originalClearAlpha );	}	renderOverride( renderer, overrideMaterial, renderTarget, clearColor, clearAlpha ) {		renderer.getClearColor( this.originalClearColor );		const originalClearAlpha = renderer.getClearAlpha();		const originalAutoClear = renderer.autoClear;		renderer.setRenderTarget( renderTarget );		renderer.autoClear = false;		clearColor = overrideMaterial.clearColor || clearColor;		clearAlpha = overrideMaterial.clearAlpha || clearAlpha;		if ( ( clearColor !== undefined ) && ( clearColor !== null ) ) {			renderer.setClearColor( clearColor );			renderer.setClearAlpha( clearAlpha || 0.0 );			renderer.clear();		}		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 );	}	setSize( width, height ) {		this.width = width;		this.height = height;		this.beautyRenderTarget.setSize( width, height );		this.ssaoRenderTarget.setSize( width, height );		this.normalRenderTarget.setSize( width, height );		this.blurRenderTarget.setSize( width, height );		this.ssaoMaterial.uniforms[ 'resolution' ].value.set( width, height );		this.ssaoMaterial.uniforms[ 'cameraProjectionMatrix' ].value.copy( this.camera.projectionMatrix );		this.ssaoMaterial.uniforms[ 'cameraInverseProjectionMatrix' ].value.copy( this.camera.projectionMatrixInverse );		this.blurMaterial.uniforms[ 'resolution' ].value.set( width, height );	}	generateSampleKernel() {		const kernelSize = this.kernelSize;		const kernel = this.kernel;		for ( let i = 0; i < kernelSize; i ++ ) {			const sample = new Vector3();			sample.x = ( Math.random() * 2 ) - 1;			sample.y = ( Math.random() * 2 ) - 1;			sample.z = Math.random();			sample.normalize();			let scale = i / kernelSize;			scale = MathUtils.lerp( 0.1, 1, scale * scale );			sample.multiplyScalar( scale );			kernel.push( sample );		}	}	generateRandomKernelRotations() {		const width = 4, height = 4;		if ( SimplexNoise === undefined ) {			console.error( 'THREE.SSAOPass: The pass relies on SimplexNoise.' );		}		const simplex = new SimplexNoise();		const size = width * height;		const data = new Float32Array( size * 4 );		for ( let i = 0; i < size; i ++ ) {			const stride = i * 4;			const x = ( Math.random() * 2 ) - 1;			const y = ( Math.random() * 2 ) - 1;			const z = 0;			const noise = simplex.noise3d( x, y, z );			data[ stride ] = noise;			data[ stride + 1 ] = noise;			data[ stride + 2 ] = noise;			data[ stride + 3 ] = 1;		}		this.noiseTexture = new DataTexture( data, width, height, RGBAFormat, FloatType );		this.noiseTexture.wrapS = RepeatWrapping;		this.noiseTexture.wrapT = RepeatWrapping;	}	overrideVisibility() {		const scene = this.scene;		const cache = this._visibilityCache;		scene.traverse( function ( object ) {			cache.set( object, object.visible );			if ( object.isPoints || object.isLine ) object.visible = false;		} );	}	restoreVisibility() {		const scene = this.scene;		const cache = this._visibilityCache;		scene.traverse( function ( object ) {			const visible = cache.get( object );			object.visible = visible;		} );		cache.clear();	}}SSAOPass.OUTPUT = {	'Default': 0,	'SSAO': 1,	'Blur': 2,	'Beauty': 3,	'Depth': 4,	'Normal': 5};export { SSAOPass };
 |