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