From d11d1de794f544d88ed6dbdb5fe86e27d7e017f4 Mon Sep 17 00:00:00 2001
From: luxiaotao1123 <t1341870251@63.com>
Date: 星期五, 31 十二月 2021 11:10:30 +0800
Subject: [PATCH] #

---
 static/js/lib/EffectComposer.js             |  318 +++++++++++++++++++++++++++++++
 static/js/app.js                            |   12 +
 static/js/lib/postprocessing/ShaderPass.js  |   68 ++++++
 static/js/lib/postprocessing/RenderPass.js  |   81 ++++++++
 static/js/lib/postprocessing/Pass.js        |    2 
 static/js/lib/postprocessing/MaskPass.js    |  101 ++++++++++
 static/js/lib/postprocessing/OutlinePass.js |    6 
 7 files changed, 583 insertions(+), 5 deletions(-)

diff --git a/static/js/app.js b/static/js/app.js
index 26215d3..5cc0647 100644
--- a/static/js/app.js
+++ b/static/js/app.js
@@ -1,7 +1,10 @@
 import {OrbitControls} from './lib/OrbitControls.js';
 import { PointerLockControls } from './lib/PointerLockControls.js';
 import Stats from './lib/stats.module.js';
-import { OutlinePass } from './lib/OutlinePass.js';
+import { EffectComposer } from './lib/EffectComposer.js';
+import { RenderPass } from './lib/postprocessing/RenderPass.js';
+import { ShaderPass } from './lib/postprocessing/ShaderPass.js';
+import { OutlinePass } from './lib/postprocessing/OutlinePass.js';
 import {MTLLoader} from './lib/MTLLoader.js';
 import {OBJLoader} from './lib/OBJLoader.js';
 import {StoreShelf} from './object/StoreShelf.js';
@@ -49,6 +52,7 @@
 			this.initLight();
 			this.initReSize(this);
 			this.initOutLine();
+			this.initComposer();
 			this.initObjectSelect();
 			this.initPointLockControl(this);
 			this.initFloor();
@@ -192,6 +196,12 @@
 			this.outlinePass.visibleEdgeColor.set('#B31985');//鍖呭洿绾块鑹�
 			this.outlinePass.hiddenEdgeColor.set('#190a05');//琚伄鎸$殑杈圭晫绾块鑹�
 		}
+		this.initComposer = function(){
+			this.composer = new EffectComposer(this.renderer);
+			const renderPass = new RenderPass( this.scene, this.camera );
+			this.composer.addPass( renderPass );
+			this.composer.addPass(this.outlinePass);
+		}
 		this.initObjectSelect = function(){
 			new ObjectSelect(this.scene, this.camera, this.outlinePass);
 		}
diff --git a/static/js/lib/EffectComposer.js b/static/js/lib/EffectComposer.js
new file mode 100644
index 0000000..41de44d
--- /dev/null
+++ b/static/js/lib/EffectComposer.js
@@ -0,0 +1,318 @@
+import {
+	BufferGeometry,
+	Clock,
+	Float32BufferAttribute,
+	LinearFilter,
+	Mesh,
+	OrthographicCamera,
+	RGBAFormat,
+	Vector2,
+	WebGLRenderTarget
+} from '../three.module.js';
+import { CopyShader } from '../lib/CopyShader.js';
+import { ShaderPass } from '../lib/postprocessing/ShaderPass.js';
+import { MaskPass } from '../lib/postprocessing/MaskPass.js';
+import { ClearMaskPass } from '../lib/postprocessing/MaskPass.js';
+
+class EffectComposer {
+
+	constructor( renderer, renderTarget ) {
+
+		this.renderer = renderer;
+
+		if ( renderTarget === undefined ) {
+
+			const parameters = {
+				minFilter: LinearFilter,
+				magFilter: LinearFilter,
+				format: RGBAFormat
+			};
+
+			const size = renderer.getSize( new Vector2() );
+			this._pixelRatio = renderer.getPixelRatio();
+			this._width = size.width;
+			this._height = size.height;
+
+			renderTarget = new WebGLRenderTarget( this._width * this._pixelRatio, this._height * this._pixelRatio, parameters );
+			renderTarget.texture.name = 'EffectComposer.rt1';
+
+		} else {
+
+			this._pixelRatio = 1;
+			this._width = renderTarget.width;
+			this._height = renderTarget.height;
+
+		}
+
+		this.renderTarget1 = renderTarget;
+		this.renderTarget2 = renderTarget.clone();
+		this.renderTarget2.texture.name = 'EffectComposer.rt2';
+
+		this.writeBuffer = this.renderTarget1;
+		this.readBuffer = this.renderTarget2;
+
+		this.renderToScreen = true;
+
+		this.passes = [];
+
+		// dependencies
+
+		if ( CopyShader === undefined ) {
+
+			console.error( 'THREE.EffectComposer relies on CopyShader' );
+
+		}
+
+		if ( ShaderPass === undefined ) {
+
+			console.error( 'THREE.EffectComposer relies on ShaderPass' );
+
+		}
+
+		this.copyPass = new ShaderPass( CopyShader );
+
+		this.clock = new Clock();
+
+	}
+
+	swapBuffers() {
+
+		const tmp = this.readBuffer;
+		this.readBuffer = this.writeBuffer;
+		this.writeBuffer = tmp;
+
+	}
+
+	addPass( pass ) {
+
+		this.passes.push( pass );
+		pass.setSize( this._width * this._pixelRatio, this._height * this._pixelRatio );
+
+	}
+
+	insertPass( pass, index ) {
+
+		this.passes.splice( index, 0, pass );
+		pass.setSize( this._width * this._pixelRatio, this._height * this._pixelRatio );
+
+	}
+
+	removePass( pass ) {
+
+		const index = this.passes.indexOf( pass );
+
+		if ( index !== - 1 ) {
+
+			this.passes.splice( index, 1 );
+
+		}
+
+	}
+
+	isLastEnabledPass( passIndex ) {
+
+		for ( let i = passIndex + 1; i < this.passes.length; i ++ ) {
+
+			if ( this.passes[ i ].enabled ) {
+
+				return false;
+
+			}
+
+		}
+
+		return true;
+
+	}
+
+	render( deltaTime ) {
+
+		// deltaTime value is in seconds
+
+		if ( deltaTime === undefined ) {
+
+			deltaTime = this.clock.getDelta();
+
+		}
+
+		const currentRenderTarget = this.renderer.getRenderTarget();
+
+		let maskActive = false;
+
+		for ( let i = 0, il = this.passes.length; i < il; i ++ ) {
+
+			const pass = this.passes[ i ];
+
+			if ( pass.enabled === false ) continue;
+
+			pass.renderToScreen = ( this.renderToScreen && this.isLastEnabledPass( i ) );
+			pass.render( this.renderer, this.writeBuffer, this.readBuffer, deltaTime, maskActive );
+
+			if ( pass.needsSwap ) {
+
+				if ( maskActive ) {
+
+					const context = this.renderer.getContext();
+					const stencil = this.renderer.state.buffers.stencil;
+
+					//context.stencilFunc( context.NOTEQUAL, 1, 0xffffffff );
+					stencil.setFunc( context.NOTEQUAL, 1, 0xffffffff );
+
+					this.copyPass.render( this.renderer, this.writeBuffer, this.readBuffer, deltaTime );
+
+					//context.stencilFunc( context.EQUAL, 1, 0xffffffff );
+					stencil.setFunc( context.EQUAL, 1, 0xffffffff );
+
+				}
+
+				this.swapBuffers();
+
+			}
+
+			if ( MaskPass !== undefined ) {
+
+				if ( pass instanceof MaskPass ) {
+
+					maskActive = true;
+
+				} else if ( pass instanceof ClearMaskPass ) {
+
+					maskActive = false;
+
+				}
+
+			}
+
+		}
+
+		this.renderer.setRenderTarget( currentRenderTarget );
+
+	}
+
+	reset( renderTarget ) {
+
+		if ( renderTarget === undefined ) {
+
+			const size = this.renderer.getSize( new Vector2() );
+			this._pixelRatio = this.renderer.getPixelRatio();
+			this._width = size.width;
+			this._height = size.height;
+
+			renderTarget = this.renderTarget1.clone();
+			renderTarget.setSize( this._width * this._pixelRatio, this._height * this._pixelRatio );
+
+		}
+
+		this.renderTarget1.dispose();
+		this.renderTarget2.dispose();
+		this.renderTarget1 = renderTarget;
+		this.renderTarget2 = renderTarget.clone();
+
+		this.writeBuffer = this.renderTarget1;
+		this.readBuffer = this.renderTarget2;
+
+	}
+
+	setSize( width, height ) {
+
+		this._width = width;
+		this._height = height;
+
+		const effectiveWidth = this._width * this._pixelRatio;
+		const effectiveHeight = this._height * this._pixelRatio;
+
+		this.renderTarget1.setSize( effectiveWidth, effectiveHeight );
+		this.renderTarget2.setSize( effectiveWidth, effectiveHeight );
+
+		for ( let i = 0; i < this.passes.length; i ++ ) {
+
+			this.passes[ i ].setSize( effectiveWidth, effectiveHeight );
+
+		}
+
+	}
+
+	setPixelRatio( pixelRatio ) {
+
+		this._pixelRatio = pixelRatio;
+
+		this.setSize( this._width, this._height );
+
+	}
+
+}
+
+
+class Pass {
+
+	constructor() {
+
+		// if set to true, the pass is processed by the composer
+		this.enabled = true;
+
+		// if set to true, the pass indicates to swap read and write buffer after rendering
+		this.needsSwap = true;
+
+		// if set to true, the pass clears its buffer before rendering
+		this.clear = false;
+
+		// if set to true, the result of the pass is rendered to screen. This is set automatically by EffectComposer.
+		this.renderToScreen = false;
+
+	}
+
+	setSize( /* width, height */ ) {}
+
+	render( /* renderer, writeBuffer, readBuffer, deltaTime, maskActive */ ) {
+
+		console.error( 'THREE.Pass: .render() must be implemented in derived pass.' );
+
+	}
+
+}
+
+// Helper for passes that need to fill the viewport with a single quad.
+
+const _camera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
+
+// https://github.com/mrdoob/three.js/pull/21358
+
+const _geometry = new BufferGeometry();
+_geometry.setAttribute( 'position', new Float32BufferAttribute( [ - 1, 3, 0, - 1, - 1, 0, 3, - 1, 0 ], 3 ) );
+_geometry.setAttribute( 'uv', new Float32BufferAttribute( [ 0, 2, 0, 0, 2, 0 ], 2 ) );
+
+class FullScreenQuad {
+
+	constructor( material ) {
+
+		this._mesh = new Mesh( _geometry, material );
+
+	}
+
+	dispose() {
+
+		this._mesh.geometry.dispose();
+
+	}
+
+	render( renderer ) {
+
+		renderer.render( this._mesh, _camera );
+
+	}
+
+	get material() {
+
+		return this._mesh.material;
+
+	}
+
+	set material( value ) {
+
+		this._mesh.material = value;
+
+	}
+
+}
+
+export { EffectComposer, Pass, FullScreenQuad };
diff --git a/static/js/lib/postprocessing/MaskPass.js b/static/js/lib/postprocessing/MaskPass.js
new file mode 100644
index 0000000..09b396b
--- /dev/null
+++ b/static/js/lib/postprocessing/MaskPass.js
@@ -0,0 +1,101 @@
+import { Pass } from '../../lib/postprocessing/Pass.js';
+
+class MaskPass extends Pass {
+
+	constructor( scene, camera ) {
+
+		super();
+
+		this.scene = scene;
+		this.camera = camera;
+
+		this.clear = true;
+		this.needsSwap = false;
+
+		this.inverse = false;
+
+	}
+
+	render( renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {
+
+		const context = renderer.getContext();
+		const state = renderer.state;
+
+		// don't update color or depth
+
+		state.buffers.color.setMask( false );
+		state.buffers.depth.setMask( false );
+
+		// lock buffers
+
+		state.buffers.color.setLocked( true );
+		state.buffers.depth.setLocked( true );
+
+		// set up stencil
+
+		let writeValue, clearValue;
+
+		if ( this.inverse ) {
+
+			writeValue = 0;
+			clearValue = 1;
+
+		} else {
+
+			writeValue = 1;
+			clearValue = 0;
+
+		}
+
+		state.buffers.stencil.setTest( true );
+		state.buffers.stencil.setOp( context.REPLACE, context.REPLACE, context.REPLACE );
+		state.buffers.stencil.setFunc( context.ALWAYS, writeValue, 0xffffffff );
+		state.buffers.stencil.setClear( clearValue );
+		state.buffers.stencil.setLocked( true );
+
+		// draw into the stencil buffer
+
+		renderer.setRenderTarget( readBuffer );
+		if ( this.clear ) renderer.clear();
+		renderer.render( this.scene, this.camera );
+
+		renderer.setRenderTarget( writeBuffer );
+		if ( this.clear ) renderer.clear();
+		renderer.render( this.scene, this.camera );
+
+		// unlock color and depth buffer for subsequent rendering
+
+		state.buffers.color.setLocked( false );
+		state.buffers.depth.setLocked( false );
+
+		// only render where stencil is set to 1
+
+		state.buffers.stencil.setLocked( false );
+		state.buffers.stencil.setFunc( context.EQUAL, 1, 0xffffffff ); // draw if == 1
+		state.buffers.stencil.setOp( context.KEEP, context.KEEP, context.KEEP );
+		state.buffers.stencil.setLocked( true );
+
+	}
+
+}
+
+class ClearMaskPass extends Pass {
+
+	constructor() {
+
+		super();
+
+		this.needsSwap = false;
+
+	}
+
+	render( renderer /*, writeBuffer, readBuffer, deltaTime, maskActive */ ) {
+
+		renderer.state.buffers.stencil.setLocked( false );
+		renderer.state.buffers.stencil.setTest( false );
+
+	}
+
+}
+
+export { MaskPass, ClearMaskPass };
diff --git a/static/js/lib/OutlinePass.js b/static/js/lib/postprocessing/OutlinePass.js
similarity index 98%
rename from static/js/lib/OutlinePass.js
rename to static/js/lib/postprocessing/OutlinePass.js
index 08563ed..e60e04e 100644
--- a/static/js/lib/OutlinePass.js
+++ b/static/js/lib/postprocessing/OutlinePass.js
@@ -14,9 +14,9 @@
 	Vector2,
 	Vector3,
 	WebGLRenderTarget
-} from '../three.module.js';
-import { Pass, FullScreenQuad } from '../lib/Pass.js';
-import { CopyShader } from '../lib/CopyShader.js';
+} from '../../three.module.js';
+import { Pass, FullScreenQuad } from '../../lib/postprocessing/Pass.js';
+import { CopyShader } from '../../lib/CopyShader.js';
 
 class OutlinePass extends Pass {
 
diff --git a/static/js/lib/Pass.js b/static/js/lib/postprocessing/Pass.js
similarity index 97%
rename from static/js/lib/Pass.js
rename to static/js/lib/postprocessing/Pass.js
index 30eb17c..013e9ef 100644
--- a/static/js/lib/Pass.js
+++ b/static/js/lib/postprocessing/Pass.js
@@ -3,7 +3,7 @@
 	Float32BufferAttribute,
 	OrthographicCamera,
 	Mesh
-} from '../three.module.js';
+} from '../../three.module.js';
 
 class Pass {
 
diff --git a/static/js/lib/postprocessing/RenderPass.js b/static/js/lib/postprocessing/RenderPass.js
new file mode 100644
index 0000000..c97a0d9
--- /dev/null
+++ b/static/js/lib/postprocessing/RenderPass.js
@@ -0,0 +1,81 @@
+import {
+	Color
+} from '../../three.module.js';
+import { Pass } from '../../lib/postprocessing/Pass.js';
+
+class RenderPass extends Pass {
+
+	constructor( scene, camera, overrideMaterial, clearColor, clearAlpha ) {
+
+		super();
+
+		this.scene = scene;
+		this.camera = camera;
+
+		this.overrideMaterial = overrideMaterial;
+
+		this.clearColor = clearColor;
+		this.clearAlpha = ( clearAlpha !== undefined ) ? clearAlpha : 0;
+
+		this.clear = true;
+		this.clearDepth = false;
+		this.needsSwap = false;
+		this._oldClearColor = new Color();
+
+	}
+
+	render( renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {
+
+		const oldAutoClear = renderer.autoClear;
+		renderer.autoClear = false;
+
+		let oldClearAlpha, oldOverrideMaterial;
+
+		if ( this.overrideMaterial !== undefined ) {
+
+			oldOverrideMaterial = this.scene.overrideMaterial;
+
+			this.scene.overrideMaterial = this.overrideMaterial;
+
+		}
+
+		if ( this.clearColor ) {
+
+			renderer.getClearColor( this._oldClearColor );
+			oldClearAlpha = renderer.getClearAlpha();
+
+			renderer.setClearColor( this.clearColor, this.clearAlpha );
+
+		}
+
+		if ( this.clearDepth ) {
+
+			renderer.clearDepth();
+
+		}
+
+		renderer.setRenderTarget( this.renderToScreen ? null : readBuffer );
+
+		// TODO: Avoid using autoClear properties, see https://github.com/mrdoob/three.js/pull/15571#issuecomment-465669600
+		if ( this.clear ) renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );
+		renderer.render( this.scene, this.camera );
+
+		if ( this.clearColor ) {
+
+			renderer.setClearColor( this._oldClearColor, oldClearAlpha );
+
+		}
+
+		if ( this.overrideMaterial !== undefined ) {
+
+			this.scene.overrideMaterial = oldOverrideMaterial;
+
+		}
+
+		renderer.autoClear = oldAutoClear;
+
+	}
+
+}
+
+export { RenderPass };
diff --git a/static/js/lib/postprocessing/ShaderPass.js b/static/js/lib/postprocessing/ShaderPass.js
new file mode 100644
index 0000000..09b5523
--- /dev/null
+++ b/static/js/lib/postprocessing/ShaderPass.js
@@ -0,0 +1,68 @@
+import {
+	ShaderMaterial,
+	UniformsUtils
+} from '../../three.module.js';
+import { Pass, FullScreenQuad } from '../../lib/postprocessing/Pass.js';
+
+class ShaderPass extends Pass {
+
+	constructor( shader, textureID ) {
+
+		super();
+
+		this.textureID = ( textureID !== undefined ) ? textureID : 'tDiffuse';
+
+		if ( shader instanceof ShaderMaterial ) {
+
+			this.uniforms = shader.uniforms;
+
+			this.material = shader;
+
+		} else if ( shader ) {
+
+			this.uniforms = UniformsUtils.clone( shader.uniforms );
+
+			this.material = new ShaderMaterial( {
+
+				defines: Object.assign( {}, shader.defines ),
+				uniforms: this.uniforms,
+				vertexShader: shader.vertexShader,
+				fragmentShader: shader.fragmentShader
+
+			} );
+
+		}
+
+		this.fsQuad = new FullScreenQuad( this.material );
+
+	}
+
+	render( renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {
+
+		if ( this.uniforms[ this.textureID ] ) {
+
+			this.uniforms[ this.textureID ].value = readBuffer.texture;
+
+		}
+
+		this.fsQuad.material = this.material;
+
+		if ( this.renderToScreen ) {
+
+			renderer.setRenderTarget( null );
+			this.fsQuad.render( renderer );
+
+		} else {
+
+			renderer.setRenderTarget( writeBuffer );
+			// TODO: Avoid using autoClear properties, see https://github.com/mrdoob/three.js/pull/15571#issuecomment-465669600
+			if ( this.clear ) renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );
+			this.fsQuad.render( renderer );
+
+		}
+
+	}
+
+}
+
+export { ShaderPass };

--
Gitblit v1.9.1