|
@@ -2,52 +2,50 @@
|
|
* @author Slayvin / http://slayvin.net
|
|
* @author Slayvin / http://slayvin.net
|
|
*/
|
|
*/
|
|
|
|
|
|
-THREE.Mirror = function ( renderer, camera, options ) {
|
|
|
|
|
|
+THREE.Mirror = function ( width, height, options ) {
|
|
|
|
|
|
- THREE.Object3D.call( this );
|
|
|
|
|
|
+ THREE.Mesh.call( this, new THREE.PlaneBufferGeometry( width, height ) );
|
|
|
|
|
|
- this.name = 'mirror_' + this.id;
|
|
|
|
|
|
+ var scope = this;
|
|
|
|
|
|
- options = options || {};
|
|
|
|
-
|
|
|
|
- this.matrixNeedsUpdate = true;
|
|
|
|
|
|
+ scope.name = 'mirror_' + scope.id;
|
|
|
|
+ scope.matrixNeedsUpdate = true;
|
|
|
|
|
|
- var width = options.textureWidth !== undefined ? options.textureWidth : 512;
|
|
|
|
- var height = options.textureHeight !== undefined ? options.textureHeight : 512;
|
|
|
|
|
|
+ options = options || {};
|
|
|
|
|
|
- this.clipBias = options.clipBias !== undefined ? options.clipBias : 0.0;
|
|
|
|
|
|
+ var textureWidth = options.textureWidth !== undefined ? options.textureWidth : 512;
|
|
|
|
+ var textureHeight = options.textureHeight !== undefined ? options.textureHeight : 512;
|
|
|
|
|
|
|
|
+ var clipBias = options.clipBias !== undefined ? options.clipBias : 0.0;
|
|
var mirrorColor = options.color !== undefined ? new THREE.Color( options.color ) : new THREE.Color( 0x7F7F7F );
|
|
var mirrorColor = options.color !== undefined ? new THREE.Color( options.color ) : new THREE.Color( 0x7F7F7F );
|
|
|
|
|
|
- this.renderer = renderer;
|
|
|
|
- this.mirrorPlane = new THREE.Plane();
|
|
|
|
- this.normal = new THREE.Vector3( 0, 0, 1 );
|
|
|
|
- this.mirrorWorldPosition = new THREE.Vector3();
|
|
|
|
- this.cameraWorldPosition = new THREE.Vector3();
|
|
|
|
- this.rotationMatrix = new THREE.Matrix4();
|
|
|
|
- this.lookAtPosition = new THREE.Vector3( 0, 0, - 1 );
|
|
|
|
- this.clipPlane = new THREE.Vector4();
|
|
|
|
|
|
+ var mirrorPlane = new THREE.Plane();
|
|
|
|
+ var normal = new THREE.Vector3();
|
|
|
|
+ var mirrorWorldPosition = new THREE.Vector3();
|
|
|
|
+ var cameraWorldPosition = new THREE.Vector3();
|
|
|
|
+ var rotationMatrix = new THREE.Matrix4();
|
|
|
|
+ var lookAtPosition = new THREE.Vector3( 0, 0, - 1 );
|
|
|
|
+ var clipPlane = new THREE.Vector4();
|
|
|
|
|
|
- if ( camera instanceof THREE.PerspectiveCamera ) {
|
|
|
|
|
|
+ var textureMatrix = new THREE.Matrix4();
|
|
|
|
|
|
- this.camera = camera;
|
|
|
|
|
|
+ var mirrorCamera = new THREE.PerspectiveCamera();
|
|
|
|
+ mirrorCamera.matrixAutoUpdate = true;
|
|
|
|
|
|
- } else {
|
|
|
|
-
|
|
|
|
- this.camera = new THREE.PerspectiveCamera();
|
|
|
|
- console.log( this.name + ': camera is not a Perspective Camera!' );
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
|
|
+ var parameters = {
|
|
|
|
+ minFilter: THREE.LinearFilter,
|
|
|
|
+ magFilter: THREE.LinearFilter,
|
|
|
|
+ format: THREE.RGBFormat,
|
|
|
|
+ stencilBuffer: false
|
|
|
|
+ };
|
|
|
|
|
|
- this.textureMatrix = new THREE.Matrix4();
|
|
|
|
|
|
+ var renderTarget = new THREE.WebGLRenderTarget( textureWidth, textureHeight, parameters );
|
|
|
|
|
|
- this.mirrorCamera = this.camera.clone();
|
|
|
|
- this.mirrorCamera.matrixAutoUpdate = true;
|
|
|
|
|
|
+ if ( ! THREE.Math.isPowerOfTwo( textureWidth ) || ! THREE.Math.isPowerOfTwo( textureHeight ) ) {
|
|
|
|
|
|
- var parameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: false };
|
|
|
|
|
|
+ renderTarget.texture.generateMipmaps = false;
|
|
|
|
|
|
- this.renderTarget = new THREE.WebGLRenderTarget( width, height, parameters );
|
|
|
|
- this.renderTarget2 = new THREE.WebGLRenderTarget( width, height, parameters );
|
|
|
|
|
|
+ }
|
|
|
|
|
|
var mirrorShader = {
|
|
var mirrorShader = {
|
|
|
|
|
|
@@ -92,7 +90,7 @@ THREE.Mirror = function ( renderer, camera, options ) {
|
|
|
|
|
|
var mirrorUniforms = THREE.UniformsUtils.clone( mirrorShader.uniforms );
|
|
var mirrorUniforms = THREE.UniformsUtils.clone( mirrorShader.uniforms );
|
|
|
|
|
|
- this.material = new THREE.ShaderMaterial( {
|
|
|
|
|
|
+ var material = new THREE.ShaderMaterial( {
|
|
|
|
|
|
fragmentShader: mirrorShader.fragmentShader,
|
|
fragmentShader: mirrorShader.fragmentShader,
|
|
vertexShader: mirrorShader.vertexShader,
|
|
vertexShader: mirrorShader.vertexShader,
|
|
@@ -100,181 +98,105 @@ THREE.Mirror = function ( renderer, camera, options ) {
|
|
|
|
|
|
} );
|
|
} );
|
|
|
|
|
|
- this.material.uniforms.mirrorSampler.value = this.renderTarget.texture;
|
|
|
|
- this.material.uniforms.mirrorColor.value = mirrorColor;
|
|
|
|
- this.material.uniforms.textureMatrix.value = this.textureMatrix;
|
|
|
|
-
|
|
|
|
- if ( ! THREE.Math.isPowerOfTwo( width ) || ! THREE.Math.isPowerOfTwo( height ) ) {
|
|
|
|
-
|
|
|
|
- this.renderTarget.texture.generateMipmaps = false;
|
|
|
|
- this.renderTarget2.texture.generateMipmaps = false;
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- this.updateTextureMatrix();
|
|
|
|
- this.render();
|
|
|
|
-
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-THREE.Mirror.prototype = Object.create( THREE.Object3D.prototype );
|
|
|
|
-
|
|
|
|
-Object.assign( THREE.Mirror.prototype, {
|
|
|
|
-
|
|
|
|
- constructor: THREE.Mirror,
|
|
|
|
-
|
|
|
|
- renderWithMirror: function ( otherMirror ) {
|
|
|
|
-
|
|
|
|
- // update the mirror matrix to mirror the current view
|
|
|
|
- this.updateTextureMatrix();
|
|
|
|
- this.matrixNeedsUpdate = false;
|
|
|
|
-
|
|
|
|
- // set the camera of the other mirror so the mirrored view is the reference view
|
|
|
|
- var tempCamera = otherMirror.camera;
|
|
|
|
- otherMirror.camera = this.mirrorCamera;
|
|
|
|
-
|
|
|
|
- // render the other mirror in temp texture
|
|
|
|
- otherMirror.renderTemp();
|
|
|
|
- otherMirror.material.uniforms.mirrorSampler.value = otherMirror.renderTarget2.texture;
|
|
|
|
|
|
+ material.uniforms.mirrorSampler.value = renderTarget.texture;
|
|
|
|
+ material.uniforms.mirrorColor.value = mirrorColor;
|
|
|
|
+ material.uniforms.textureMatrix.value = textureMatrix;
|
|
|
|
|
|
- // render the current mirror
|
|
|
|
- this.render();
|
|
|
|
- this.matrixNeedsUpdate = true;
|
|
|
|
|
|
+ scope.material = material;
|
|
|
|
|
|
- // restore material and camera of other mirror
|
|
|
|
- otherMirror.material.uniforms.mirrorSampler.value = otherMirror.renderTarget.texture;
|
|
|
|
- otherMirror.camera = tempCamera;
|
|
|
|
|
|
+ function updateTextureMatrix( camera ) {
|
|
|
|
|
|
- // restore texture matrix of other mirror
|
|
|
|
- otherMirror.updateTextureMatrix();
|
|
|
|
|
|
+ camera.updateMatrixWorld();
|
|
|
|
|
|
- },
|
|
|
|
|
|
+ mirrorCamera.copy( camera );
|
|
|
|
+ mirrorCamera.updateProjectionMatrix();
|
|
|
|
|
|
- updateTextureMatrix: function () {
|
|
|
|
|
|
+ scope.updateMatrixWorld();
|
|
|
|
|
|
- this.updateMatrixWorld();
|
|
|
|
- this.camera.updateMatrixWorld();
|
|
|
|
|
|
+ mirrorWorldPosition.setFromMatrixPosition( scope.matrixWorld );
|
|
|
|
+ cameraWorldPosition.setFromMatrixPosition( camera.matrixWorld );
|
|
|
|
|
|
- this.mirrorWorldPosition.setFromMatrixPosition( this.matrixWorld );
|
|
|
|
- this.cameraWorldPosition.setFromMatrixPosition( this.camera.matrixWorld );
|
|
|
|
|
|
+ rotationMatrix.extractRotation( scope.matrixWorld );
|
|
|
|
|
|
- this.rotationMatrix.extractRotation( this.matrixWorld );
|
|
|
|
|
|
+ normal.set( 0, 0, 1 );
|
|
|
|
+ normal.applyMatrix4( rotationMatrix );
|
|
|
|
|
|
- this.normal.set( 0, 0, 1 );
|
|
|
|
- this.normal.applyMatrix4( this.rotationMatrix );
|
|
|
|
|
|
+ var view = mirrorWorldPosition.clone().sub( cameraWorldPosition );
|
|
|
|
+ view.reflect( normal ).negate();
|
|
|
|
+ view.add( mirrorWorldPosition );
|
|
|
|
|
|
- var view = this.mirrorWorldPosition.clone().sub( this.cameraWorldPosition );
|
|
|
|
- view.reflect( this.normal ).negate();
|
|
|
|
- view.add( this.mirrorWorldPosition );
|
|
|
|
|
|
+ rotationMatrix.extractRotation( camera.matrixWorld );
|
|
|
|
|
|
- this.rotationMatrix.extractRotation( this.camera.matrixWorld );
|
|
|
|
|
|
+ lookAtPosition.set( 0, 0, - 1 );
|
|
|
|
+ lookAtPosition.applyMatrix4( rotationMatrix );
|
|
|
|
+ lookAtPosition.add( cameraWorldPosition );
|
|
|
|
|
|
- this.lookAtPosition.set( 0, 0, - 1 );
|
|
|
|
- this.lookAtPosition.applyMatrix4( this.rotationMatrix );
|
|
|
|
- this.lookAtPosition.add( this.cameraWorldPosition );
|
|
|
|
|
|
+ var target = mirrorWorldPosition.clone().sub( lookAtPosition );
|
|
|
|
+ target.reflect( normal ).negate();
|
|
|
|
+ target.add( mirrorWorldPosition );
|
|
|
|
|
|
- var target = this.mirrorWorldPosition.clone().sub( this.lookAtPosition );
|
|
|
|
- target.reflect( this.normal ).negate();
|
|
|
|
- target.add( this.mirrorWorldPosition );
|
|
|
|
|
|
+ mirrorCamera.position.copy( view );
|
|
|
|
+ mirrorCamera.up.set( 0, - 1, 0 );
|
|
|
|
+ mirrorCamera.up.applyMatrix4( rotationMatrix );
|
|
|
|
+ mirrorCamera.up.reflect( normal ).negate();
|
|
|
|
+ mirrorCamera.lookAt( target );
|
|
|
|
|
|
- this.up.set( 0, - 1, 0 );
|
|
|
|
- this.up.applyMatrix4( this.rotationMatrix );
|
|
|
|
- this.up.reflect( this.normal ).negate();
|
|
|
|
-
|
|
|
|
- this.mirrorCamera.position.copy( view );
|
|
|
|
- this.mirrorCamera.up = this.up;
|
|
|
|
- this.mirrorCamera.lookAt( target );
|
|
|
|
-
|
|
|
|
- this.mirrorCamera.updateProjectionMatrix();
|
|
|
|
- this.mirrorCamera.updateMatrixWorld();
|
|
|
|
- this.mirrorCamera.matrixWorldInverse.getInverse( this.mirrorCamera.matrixWorld );
|
|
|
|
|
|
+ mirrorCamera.updateProjectionMatrix();
|
|
|
|
+ mirrorCamera.updateMatrixWorld();
|
|
|
|
+ mirrorCamera.matrixWorldInverse.getInverse( mirrorCamera.matrixWorld );
|
|
|
|
|
|
// Update the texture matrix
|
|
// Update the texture matrix
|
|
- this.textureMatrix.set(
|
|
|
|
|
|
+ textureMatrix.set(
|
|
0.5, 0.0, 0.0, 0.5,
|
|
0.5, 0.0, 0.0, 0.5,
|
|
0.0, 0.5, 0.0, 0.5,
|
|
0.0, 0.5, 0.0, 0.5,
|
|
0.0, 0.0, 0.5, 0.5,
|
|
0.0, 0.0, 0.5, 0.5,
|
|
0.0, 0.0, 0.0, 1.0
|
|
0.0, 0.0, 0.0, 1.0
|
|
);
|
|
);
|
|
- this.textureMatrix.multiply( this.mirrorCamera.projectionMatrix );
|
|
|
|
- this.textureMatrix.multiply( this.mirrorCamera.matrixWorldInverse );
|
|
|
|
|
|
+ textureMatrix.multiply( mirrorCamera.projectionMatrix );
|
|
|
|
+ textureMatrix.multiply( mirrorCamera.matrixWorldInverse );
|
|
|
|
|
|
// Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html
|
|
// Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html
|
|
// Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
|
|
// Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
|
|
- this.mirrorPlane.setFromNormalAndCoplanarPoint( this.normal, this.mirrorWorldPosition );
|
|
|
|
- this.mirrorPlane.applyMatrix4( this.mirrorCamera.matrixWorldInverse );
|
|
|
|
|
|
+ mirrorPlane.setFromNormalAndCoplanarPoint( normal, mirrorWorldPosition );
|
|
|
|
+ mirrorPlane.applyMatrix4( mirrorCamera.matrixWorldInverse );
|
|
|
|
|
|
- this.clipPlane.set( this.mirrorPlane.normal.x, this.mirrorPlane.normal.y, this.mirrorPlane.normal.z, this.mirrorPlane.constant );
|
|
|
|
|
|
+ clipPlane.set( mirrorPlane.normal.x, mirrorPlane.normal.y, mirrorPlane.normal.z, mirrorPlane.constant );
|
|
|
|
|
|
var q = new THREE.Vector4();
|
|
var q = new THREE.Vector4();
|
|
- var projectionMatrix = this.mirrorCamera.projectionMatrix;
|
|
|
|
|
|
+ var projectionMatrix = mirrorCamera.projectionMatrix;
|
|
|
|
|
|
- q.x = ( Math.sign( this.clipPlane.x ) + projectionMatrix.elements[ 8 ] ) / projectionMatrix.elements[ 0 ];
|
|
|
|
- q.y = ( Math.sign( this.clipPlane.y ) + projectionMatrix.elements[ 9 ] ) / projectionMatrix.elements[ 5 ];
|
|
|
|
|
|
+ q.x = ( Math.sign( clipPlane.x ) + projectionMatrix.elements[ 8 ] ) / projectionMatrix.elements[ 0 ];
|
|
|
|
+ q.y = ( Math.sign( clipPlane.y ) + projectionMatrix.elements[ 9 ] ) / projectionMatrix.elements[ 5 ];
|
|
q.z = - 1.0;
|
|
q.z = - 1.0;
|
|
q.w = ( 1.0 + projectionMatrix.elements[ 10 ] ) / projectionMatrix.elements[ 14 ];
|
|
q.w = ( 1.0 + projectionMatrix.elements[ 10 ] ) / projectionMatrix.elements[ 14 ];
|
|
|
|
|
|
// Calculate the scaled plane vector
|
|
// Calculate the scaled plane vector
|
|
var c = new THREE.Vector4();
|
|
var c = new THREE.Vector4();
|
|
- c = this.clipPlane.multiplyScalar( 2.0 / this.clipPlane.dot( q ) );
|
|
|
|
|
|
+ c = clipPlane.multiplyScalar( 2.0 / clipPlane.dot( q ) );
|
|
|
|
|
|
// Replacing the third row of the projection matrix
|
|
// Replacing the third row of the projection matrix
|
|
projectionMatrix.elements[ 2 ] = c.x;
|
|
projectionMatrix.elements[ 2 ] = c.x;
|
|
projectionMatrix.elements[ 6 ] = c.y;
|
|
projectionMatrix.elements[ 6 ] = c.y;
|
|
- projectionMatrix.elements[ 10 ] = c.z + 1.0 - this.clipBias;
|
|
|
|
|
|
+ projectionMatrix.elements[ 10 ] = c.z + 1.0 - clipBias;
|
|
projectionMatrix.elements[ 14 ] = c.w;
|
|
projectionMatrix.elements[ 14 ] = c.w;
|
|
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
- render: function () {
|
|
|
|
-
|
|
|
|
- if ( this.matrixNeedsUpdate ) this.updateTextureMatrix();
|
|
|
|
-
|
|
|
|
- this.matrixNeedsUpdate = true;
|
|
|
|
-
|
|
|
|
- // Render the mirrored view of the current scene into the target texture
|
|
|
|
- var scene = this;
|
|
|
|
-
|
|
|
|
- while ( scene.parent !== null ) {
|
|
|
|
-
|
|
|
|
- scene = scene.parent;
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if ( scene !== undefined && scene instanceof THREE.Scene ) {
|
|
|
|
-
|
|
|
|
- // We can't render ourself to ourself
|
|
|
|
- var visible = this.material.visible;
|
|
|
|
- this.material.visible = false;
|
|
|
|
-
|
|
|
|
- this.renderer.render( scene, this.mirrorCamera, this.renderTarget, true );
|
|
|
|
-
|
|
|
|
- this.material.visible = visible;
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
- renderTemp: function () {
|
|
|
|
-
|
|
|
|
- if ( this.matrixNeedsUpdate ) this.updateTextureMatrix();
|
|
|
|
-
|
|
|
|
- this.matrixNeedsUpdate = true;
|
|
|
|
|
|
+ }
|
|
|
|
|
|
- // Render the mirrored view of the current scene into the target texture
|
|
|
|
- var scene = this;
|
|
|
|
|
|
+ scope.onBeforeRender = function ( renderer, scene, camera ) {
|
|
|
|
|
|
- while ( scene.parent !== null ) {
|
|
|
|
|
|
+ updateTextureMatrix( camera );
|
|
|
|
|
|
- scene = scene.parent;
|
|
|
|
|
|
+ scope.visible = false;
|
|
|
|
|
|
- }
|
|
|
|
|
|
+ var currentRenderTarget = renderer.getRenderTarget();
|
|
|
|
|
|
- if ( scene !== undefined && scene instanceof THREE.Scene ) {
|
|
|
|
|
|
+ renderer.render( scene, mirrorCamera, renderTarget, true );
|
|
|
|
+ renderer.setRenderTarget( currentRenderTarget );
|
|
|
|
|
|
- this.renderer.render( scene, this.mirrorCamera, this.renderTarget2, true );
|
|
|
|
|
|
+ scope.visible = true;
|
|
|
|
|
|
- }
|
|
|
|
|
|
+ };
|
|
|
|
|
|
- }
|
|
|
|
|
|
+};
|
|
|
|
|
|
-} );
|
|
|
|
|
|
+THREE.Mirror.prototype = Object.create( THREE.Mesh.prototype );
|