1/** 2 * @author Slayvin / http://slayvin.net 3 */ 4 5THREE3DP.ShaderLib[ 'mirror' ] = { 6 7 uniforms: { 8 "mirrorColor": { value: new THREE3DP.Color( 0x7F7F7F ) }, 9 "mirrorSampler": { value: null }, 10 "textureMatrix" : { value: new THREE3DP.Matrix4() } 11 }, 12 13 vertexShader: [ 14 15 "uniform mat4 textureMatrix;", 16 17 "varying vec4 mirrorCoord;", 18 19 "void main() {", 20 21 "vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", 22 "vec4 worldPosition = modelMatrix * vec4( position, 1.0 );", 23 "mirrorCoord = textureMatrix * worldPosition;", 24 25 "gl_Position = projectionMatrix * mvPosition;", 26 27 "}" 28 29 ].join( "\n" ), 30 31 fragmentShader: [ 32 33 "uniform vec3 mirrorColor;", 34 "uniform sampler2D mirrorSampler;", 35 36 "varying vec4 mirrorCoord;", 37 38 "float blendOverlay(float base, float blend) {", 39 "return( base < 0.5 ? ( 2.0 * base * blend ) : (1.0 - 2.0 * ( 1.0 - base ) * ( 1.0 - blend ) ) );", 40 "}", 41 42 "void main() {", 43 44 "vec4 color = texture2DProj(mirrorSampler, mirrorCoord);", 45 "color = vec4(blendOverlay(mirrorColor.r, color.r), blendOverlay(mirrorColor.g, color.g), blendOverlay(mirrorColor.b, color.b), 1.0);", 46 47 "gl_FragColor = color;", 48 49 "}" 50 51 ].join( "\n" ) 52 53}; 54 55THREE3DP.Mirror = function ( renderer, camera, options ) { 56 57 THREE3DP.Object3D.call( this ); 58 59 this.name = 'mirror_' + this.id; 60 61 options = options || {}; 62 63 this.matrixNeedsUpdate = true; 64 65 var width = options.textureWidth !== undefined ? options.textureWidth : 512; 66 var height = options.textureHeight !== undefined ? options.textureHeight : 512; 67 68 this.clipBias = options.clipBias !== undefined ? options.clipBias : 0.0; 69 70 var mirrorColor = options.color !== undefined ? new THREE3DP.Color( options.color ) : new THREE3DP.Color( 0x7F7F7F ); 71 72 this.renderer = renderer; 73 this.mirrorPlane = new THREE3DP.Plane(); 74 this.normal = new THREE3DP.Vector3( 0, 0, 1 ); 75 this.mirrorWorldPosition = new THREE3DP.Vector3(); 76 this.cameraWorldPosition = new THREE3DP.Vector3(); 77 this.rotationMatrix = new THREE3DP.Matrix4(); 78 this.lookAtPosition = new THREE3DP.Vector3( 0, 0, - 1 ); 79 this.clipPlane = new THREE3DP.Vector4(); 80 81 // For debug only, show the normal and plane of the mirror 82 var debugMode = options.debugMode !== undefined ? options.debugMode : false; 83 84 if ( debugMode ) { 85 86 var arrow = new THREE3DP.ArrowHelper( new THREE3DP.Vector3( 0, 0, 1 ), new THREE3DP.Vector3( 0, 0, 0 ), 10, 0xffff80 ); 87 var planeGeometry = new THREE3DP.Geometry(); 88 planeGeometry.vertices.push( new THREE3DP.Vector3( - 10, - 10, 0 ) ); 89 planeGeometry.vertices.push( new THREE3DP.Vector3( 10, - 10, 0 ) ); 90 planeGeometry.vertices.push( new THREE3DP.Vector3( 10, 10, 0 ) ); 91 planeGeometry.vertices.push( new THREE3DP.Vector3( - 10, 10, 0 ) ); 92 planeGeometry.vertices.push( planeGeometry.vertices[ 0 ] ); 93 var plane = new THREE3DP.Line( planeGeometry, new THREE3DP.LineBasicMaterial( { color: 0xffff80 } ) ); 94 95 this.add( arrow ); 96 this.add( plane ); 97 98 } 99 100 if ( camera instanceof THREE3DP.PerspectiveCamera ) { 101 102 this.camera = camera; 103 104 } else { 105 106 this.camera = new THREE3DP.PerspectiveCamera(); 107 console.log( this.name + ': camera is not a Perspective Camera!' ); 108 109 } 110 111 this.textureMatrix = new THREE3DP.Matrix4(); 112 113 this.mirrorCamera = this.camera.clone(); 114 this.mirrorCamera.matrixAutoUpdate = true; 115 116 var parameters = { minFilter: THREE3DP.LinearFilter, magFilter: THREE3DP.LinearFilter, format: THREE3DP.RGBFormat, stencilBuffer: false }; 117 118 this.renderTarget = new THREE3DP.WebGLRenderTarget( width, height, parameters ); 119 this.renderTarget2 = new THREE3DP.WebGLRenderTarget( width, height, parameters ); 120 121 var mirrorShader = THREE3DP.ShaderLib[ "mirror" ]; 122 var mirrorUniforms = THREE3DP.UniformsUtils.clone( mirrorShader.uniforms ); 123 124 this.material = new THREE3DP.ShaderMaterial( { 125 126 fragmentShader: mirrorShader.fragmentShader, 127 vertexShader: mirrorShader.vertexShader, 128 uniforms: mirrorUniforms 129 130 } ); 131 132 this.material.uniforms.mirrorSampler.value = this.renderTarget.texture; 133 this.material.uniforms.mirrorColor.value = mirrorColor; 134 this.material.uniforms.textureMatrix.value = this.textureMatrix; 135 136 if ( ! THREE3DP.Math.isPowerOfTwo( width ) || ! THREE3DP.Math.isPowerOfTwo( height ) ) { 137 138 this.renderTarget.texture.generateMipmaps = false; 139 this.renderTarget2.texture.generateMipmaps = false; 140 141 } 142 143 this.updateTextureMatrix(); 144 this.render(); 145 146}; 147 148THREE3DP.Mirror.prototype = Object.create( THREE3DP.Object3D.prototype ); 149THREE3DP.Mirror.prototype.constructor = THREE3DP.Mirror; 150 151THREE3DP.Mirror.prototype.renderWithMirror = function ( otherMirror ) { 152 153 // update the mirror matrix to mirror the current view 154 this.updateTextureMatrix(); 155 this.matrixNeedsUpdate = false; 156 157 // set the camera of the other mirror so the mirrored view is the reference view 158 var tempCamera = otherMirror.camera; 159 otherMirror.camera = this.mirrorCamera; 160 161 // render the other mirror in temp texture 162 otherMirror.renderTemp(); 163 otherMirror.material.uniforms.mirrorSampler.value = otherMirror.renderTarget2.texture; 164 165 // render the current mirror 166 this.render(); 167 this.matrixNeedsUpdate = true; 168 169 // restore material and camera of other mirror 170 otherMirror.material.uniforms.mirrorSampler.value = otherMirror.renderTarget.texture; 171 otherMirror.camera = tempCamera; 172 173 // restore texture matrix of other mirror 174 otherMirror.updateTextureMatrix(); 175 176}; 177 178THREE3DP.Mirror.prototype.updateTextureMatrix = function () { 179 180 this.updateMatrixWorld(); 181 this.camera.updateMatrixWorld(); 182 183 this.mirrorWorldPosition.setFromMatrixPosition( this.matrixWorld ); 184 this.cameraWorldPosition.setFromMatrixPosition( this.camera.matrixWorld ); 185 186 this.rotationMatrix.extractRotation( this.matrixWorld ); 187 188 this.normal.set( 0, 0, 1 );
189 this.normal.applyMatrix4( this.rotationMatrix ); 190 191 var view = this.mirrorWorldPosition.clone().sub( this.cameraWorldPosition ); 192 view.reflect( this.normal ).negate(); 193 view.add( this.mirrorWorldPosition ); 194 195 this.rotationMatrix.extractRotation( this.camera.matrixWorld ); 196 197 this.lookAtPosition.set( 0, 0, - 1 ); 198 this.lookAtPosition.applyMatrix4( this.rotationMatrix ); 199 this.lookAtPosition.add( this.cameraWorldPosition ); 200 201 var target = this.mirrorWorldPosition.clone().sub( this.lookAtPosition ); 202 target.reflect( this.normal ).negate(); 203 target.add( this.mirrorWorldPosition ); 204 205 this.up.set( 0, - 1, 0 ); 206 this.up.applyMatrix4( this.rotationMatrix ); 207 this.up.reflect( this.normal ).negate(); 208 209 this.mirrorCamera.position.copy( view ); 210 this.mirrorCamera.up = this.up; 211 this.mirrorCamera.lookAt( target ); 212 213 this.mirrorCamera.updateProjectionMatrix(); 214 this.mirrorCamera.updateMatrixWorld(); 215 this.mirrorCamera.matrixWorldInverse.getInverse( this.mirrorCamera.matrixWorld ); 216 217 // Update the texture matrix 218 this.textureMatrix.set( 0.5, 0.0, 0.0, 0.5, 219 0.0, 0.5, 0.0, 0.5, 220 0.0, 0.0, 0.5, 0.5, 221 0.0, 0.0, 0.0, 1.0 ); 222 this.textureMatrix.multiply( this.mirrorCamera.projectionMatrix ); 223 this.textureMatrix.multiply( this.mirrorCamera.matrixWorldInverse ); 224 225 // Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html 226 // Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf 227 this.mirrorPlane.setFromNormalAndCoplanarPoint( this.normal, this.mirrorWorldPosition ); 228 this.mirrorPlane.applyMatrix4( this.mirrorCamera.matrixWorldInverse ); 229 230 this.clipPlane.set( this.mirrorPlane.normal.x, this.mirrorPlane.normal.y, this.mirrorPlane.normal.z, this.mirrorPlane.constant ); 231 232 var q = new THREE3DP.Vector4(); 233 var projectionMatrix = this.mirrorCamera.projectionMatrix; 234 235 q.x = ( Math.sign( this.clipPlane.x ) + projectionMatrix.elements[ 8 ] ) / projectionMatrix.elements[ 0 ]; 236 q.y = ( Math.sign( this.clipPlane.y ) + projectionMatrix.elements[ 9 ] ) / projectionMatrix.elements[ 5 ]; 237 q.z = - 1.0; 238 q.w = ( 1.0 + projectionMatrix.elements[ 10 ] ) / projectionMatrix.elements[ 14 ]; 239 240 // Calculate the scaled plane vector 241 var c = new THREE3DP.Vector4(); 242 c = this.clipPlane.multiplyScalar( 2.0 / this.clipPlane.dot( q ) ); 243 244 // Replacing the third row of the projection matrix 245 projectionMatrix.elements[ 2 ] = c.x; 246 projectionMatrix.elements[ 6 ] = c.y; 247 projectionMatrix.elements[ 10 ] = c.z + 1.0 - this.clipBias; 248 projectionMatrix.elements[ 14 ] = c.w; 249 250}; 251 252THREE3DP.Mirror.prototype.render = function () { 253 254 if ( this.matrixNeedsUpdate ) this.updateTextureMatrix(); 255 256 this.matrixNeedsUpdate = true; 257 258 // Render the mirrored view of the current scene into the target texture 259 var scene = this; 260 261 while ( scene.parent !== null ) { 262 263 scene = scene.parent; 264 265 } 266 267 if ( scene !== undefined && scene instanceof THREE3DP.Scene ) { 268 269 // We can't render ourself to ourself 270 var visible = this.material.visible; 271 this.material.visible = false; 272 273 this.renderer.render( scene, this.mirrorCamera, this.renderTarget, true ); 274 275 this.material.visible = visible; 276 277 } 278 279}; 280 281THREE3DP.Mirror.prototype.renderTemp = function () { 282 283 if ( this.matrixNeedsUpdate ) this.updateTextureMatrix(); 284 285 this.matrixNeedsUpdate = true; 286 287 // Render the mirrored view of the current scene into the target texture 288 var scene = this; 289 290 while ( scene.parent !== null ) { 291 292 scene = scene.parent; 293 294 } 295 296 if ( scene !== undefined && scene instanceof THREE3DP.Scene ) { 297 298 this.renderer.render( scene, this.mirrorCamera, this.renderTarget2, true ); 299 300 } 301 302};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.