1( function () { 2 3 /** 4 * Work based on : 5 * http://slayvin.net : Flat mirror for three.js 6 * http://www.adelphi.edu/~stemkoski : An implementation of water shader based on the flat mirror 7 * http://29a.ch/ && http://29a.ch/slides/2012/webglwater/ : Water shader explanations in WebGL 8 */ 9 10 class Water extends THREE.Mesh { 11 12 constructor( geometry, options = {} ) { 13 14 super( geometry ); 15 const scope = this; 16 const textureWidth = options.textureWidth !== undefined ? options.textureWidth : 512; 17 const textureHeight = options.textureHeight !== undefined ? options.textureHeight : 512; 18 const clipBias = options.clipBias !== undefined ? options.clipBias : 0.0; 19 const alpha = options.alpha !== undefined ? options.alpha : 1.0; 20 const time = options.time !== undefined ? options.time : 0.0; 21 const normalSampler = options.waterNormals !== undefined ? options.waterNormals : null; 22 const sunDirection = options.sunDirection !== undefined ? options.sunDirection : new THREE.Vector3( 0.70707, 0.70707, 0.0 ); 23 const sunColor = new THREE.Color( options.sunColor !== undefined ? options.sunColor : 0xffffff ); 24 const waterColor = new THREE.Color( options.waterColor !== undefined ? options.waterColor : 0x7F7F7F ); 25 const eye = options.eye !== undefined ? options.eye : new THREE.Vector3( 0, 0, 0 ); 26 const distortionScale = options.distortionScale !== undefined ? options.distortionScale : 20.0; 27 const side = options.side !== undefined ? options.side : THREE.FrontSide; 28 const fog = options.fog !== undefined ? options.fog : false; // 29 30 const mirrorPlane = new THREE.Plane(); 31 const normal = new THREE.Vector3(); 32 const mirrorWorldPosition = new THREE.Vector3(); 33 const cameraWorldPosition = new THREE.Vector3(); 34 const rotationMatrix = new THREE.Matrix4(); 35 const lookAtPosition = new THREE.Vector3( 0, 0, - 1 ); 36 const clipPlane = new THREE.Vector4(); 37 const view = new THREE.Vector3(); 38 const target = new THREE.Vector3(); 39 const q = new THREE.Vector4(); 40 const textureMatrix = new THREE.Matrix4(); 41 const mirrorCamera = new THREE.PerspectiveCamera(); 42 const parameters = { 43 minFilter: THREE.LinearFilter, 44 magFilter: THREE.LinearFilter, 45 format: THREE.RGBFormat 46 }; 47 const renderTarget = new THREE.WebGLRenderTarget( textureWidth, textureHeight, parameters ); 48 49 if ( ! THREE.MathUtils.isPowerOfTwo( textureWidth ) || ! THREE.MathUtils.isPowerOfTwo( textureHeight ) ) { 50 51 renderTarget.texture.generateMipmaps = false; 52 53 } 54 55 const mirrorShader = { 56 uniforms: THREE.UniformsUtils.merge( [ THREE.UniformsLib[ 'fog' ], THREE.UniformsLib[ 'lights' ], { 57 'normalSampler': { 58 value: null 59 }, 60 'mirrorSampler': { 61 value: null 62 }, 63 'alpha': { 64 value: 1.0 65 }, 66 'time': { 67 value: 0.0 68 }, 69 'size': { 70 value: 1.0 71 }, 72 'distortionScale': { 73 value: 20.0 74 }, 75 'textureMatrix': { 76 value: new THREE.Matrix4() 77 }, 78 'sunColor': { 79 value: new THREE.Color( 0x7F7F7F ) 80 }, 81 'sunDirection': { 82 value: new THREE.Vector3( 0.70707, 0.70707, 0 ) 83 }, 84 'eye': { 85 value: new THREE.Vector3() 86 }, 87 'waterColor': { 88 value: new THREE.Color( 0x555555 ) 89 } 90 } ] ), 91 vertexShader: 92 /* glsl */ 93 ` 94 uniform mat4 textureMatrix; 95 uniform float time; 96 97 varying vec4 mirrorCoord; 98 varying vec4 worldPosition; 99 100 #include <common> 101 #include <fog_pars_vertex> 102 #include <shadowmap_pars_vertex> 103 #include <logdepthbuf_pars_vertex> 104 105 void main() { 106 mirrorCoord = modelMatrix * vec4( position, 1.0 ); 107 worldPosition = mirrorCoord.xyzw; 108 mirrorCoord = textureMatrix * mirrorCoord; 109 vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 ); 110 gl_Position = projectionMatrix * mvPosition; 111 112 #include <beginnormal_vertex> 113 #include <defaultnormal_vertex> 114 #include <logdepthbuf_vertex> 115 #include <fog_vertex> 116 #include <shadowmap_vertex> 117 }`, 118 fragmentShader: 119 /* glsl */ 120 ` 121 uniform sampler2D mirrorSampler; 122 uniform float alpha; 123 uniform float time; 124 uniform float size; 125 uniform float distortionScale; 126 uniform sampler2D normalSampler; 127 uniform vec3 sunColor; 128 uniform vec3 sunDirection; 129 uniform vec3 eye; 130 uniform vec3 waterColor; 131 132 varying vec4 mirrorCoord; 133 varying vec4 worldPosition; 134 135 vec4 getNoise( vec2 uv ) { 136 vec2 uv0 = ( uv / 103.0 ) + vec2(time / 17.0, time / 29.0); 137 vec2 uv1 = uv / 107.0-vec2( time / -19.0, time / 31.0 ); 138 vec2 uv2 = uv / vec2( 8907.0, 9803.0 ) + vec2( time / 101.0, time / 97.0 ); 139 vec2 uv3 = uv / vec2( 1091.0, 1027.0 ) - vec2( time / 109.0, time / -113.0 ); 140 vec4 noise = texture2D( normalSampler, uv0 ) + 141 texture2D( normalSampler, uv1 ) + 142 texture2D( normalSampler, uv2 ) + 143 texture2D( normalSampler, uv3 ); 144 return noise * 0.5 - 1.0; 145 } 146 147 void sunLight( const vec3 surfaceNormal, const vec3 eyeDirection, float shiny, float spec, float diffuse, inout vec3 diffuseColor, inout vec3 specularColor ) { 148 vec3 reflection = normalize( reflect( -sunDirection, surfaceNormal ) ); 149 float direction = max( 0.0, dot( eyeDirection, reflection ) ); 150 specularColor += pow( direction, shiny ) * sunColor * spec; 151 diffuseColor += max( dot( sunDirection, surfaceNormal ), 0.0 ) * sunColor * diffuse; 152 } 153 154 #include <common> 155 #include <packing> 156 #include <bsdfs> 157 #include <fog_pars_fragment> 158 #include <logdepthbuf_pars_fragment> 159 #include <lights_pars_begin> 160 #include <shadowmap_pars_fragment> 161 #include <shadowmask_pars_fragment> 162 163 void main() { 164 165 #include <logdepthbuf_fragment> 166 vec4 noise = getNoise( worldPosition.xz * size ); 167 vec3 surfaceNormal = normalize( noise.xzy * vec3( 1.5, 1.0, 1.5 ) ); 168 169 vec3 diffuseLight = vec3(0.0); 170 vec3 specularLight = vec3(0.0); 171 172 vec3 worldToEye = eye-worldPosition.xyz;
173 vec3 eyeDirection = normalize( worldToEye ); 174 sunLight( surfaceNormal, eyeDirection, 100.0, 2.0, 0.5, diffuseLight, specularLight ); 175 176 float distance = length(worldToEye); 177 178 vec2 distortion = surfaceNormal.xz * ( 0.001 + 1.0 / distance ) * distortionScale; 179 vec3 reflectionSample = vec3( texture2D( mirrorSampler, mirrorCoord.xy / mirrorCoord.w + distortion ) ); 180 181 float theta = max( dot( eyeDirection, surfaceNormal ), 0.0 ); 182 float rf0 = 0.3; 183 float reflectance = rf0 + ( 1.0 - rf0 ) * pow( ( 1.0 - theta ), 5.0 ); 184 vec3 scatter = max( 0.0, dot( surfaceNormal, eyeDirection ) ) * waterColor; 185 vec3 albedo = mix( ( sunColor * diffuseLight * 0.3 + scatter ) * getShadowMask(), ( vec3( 0.1 ) + reflectionSample * 0.9 + reflectionSample * specularLight ), reflectance); 186 vec3 outgoingLight = albedo; 187 gl_FragColor = vec4( outgoingLight, alpha ); 188 189 #include <tonemapping_fragment> 190 #include <fog_fragment> 191 }` 192 }; 193 const material = new THREE.ShaderMaterial( { 194 fragmentShader: mirrorShader.fragmentShader, 195 vertexShader: mirrorShader.vertexShader, 196 uniforms: THREE.UniformsUtils.clone( mirrorShader.uniforms ), 197 lights: true, 198 side: side, 199 fog: fog 200 } ); 201 material.uniforms[ 'mirrorSampler' ].value = renderTarget.texture; 202 material.uniforms[ 'textureMatrix' ].value = textureMatrix; 203 material.uniforms[ 'alpha' ].value = alpha; 204 material.uniforms[ 'time' ].value = time; 205 material.uniforms[ 'normalSampler' ].value = normalSampler; 206 material.uniforms[ 'sunColor' ].value = sunColor; 207 material.uniforms[ 'waterColor' ].value = waterColor; 208 material.uniforms[ 'sunDirection' ].value = sunDirection; 209 material.uniforms[ 'distortionScale' ].value = distortionScale; 210 material.uniforms[ 'eye' ].value = eye; 211 scope.material = material; 212 213 scope.onBeforeRender = function ( renderer, scene, camera ) { 214 215 mirrorWorldPosition.setFromMatrixPosition( scope.matrixWorld ); 216 cameraWorldPosition.setFromMatrixPosition( camera.matrixWorld ); 217 rotationMatrix.extractRotation( scope.matrixWorld ); 218 normal.set( 0, 0, 1 ); 219 normal.applyMatrix4( rotationMatrix ); 220 view.subVectors( mirrorWorldPosition, cameraWorldPosition ); // Avoid rendering when mirror is facing away 221 222 if ( view.dot( normal ) > 0 ) return; 223 view.reflect( normal ).negate(); 224 view.add( mirrorWorldPosition ); 225 rotationMatrix.extractRotation( camera.matrixWorld ); 226 lookAtPosition.set( 0, 0, - 1 ); 227 lookAtPosition.applyMatrix4( rotationMatrix ); 228 lookAtPosition.add( cameraWorldPosition ); 229 target.subVectors( mirrorWorldPosition, lookAtPosition ); 230 target.reflect( normal ).negate(); 231 target.add( mirrorWorldPosition ); 232 mirrorCamera.position.copy( view ); 233 mirrorCamera.up.set( 0, 1, 0 ); 234 mirrorCamera.up.applyMatrix4( rotationMatrix ); 235 mirrorCamera.up.reflect( normal ); 236 mirrorCamera.lookAt( target ); 237 mirrorCamera.far = camera.far; // Used in WebGLBackground 238 239 mirrorCamera.updateMatrixWorld(); 240 mirrorCamera.projectionMatrix.copy( camera.projectionMatrix ); // Update the texture matrix 241 242 textureMatrix.set( 0.5, 0.0, 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.0, 1.0 ); 243 textureMatrix.multiply( mirrorCamera.projectionMatrix ); 244 textureMatrix.multiply( mirrorCamera.matrixWorldInverse ); // Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html 245 // Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf 246 247 mirrorPlane.setFromNormalAndCoplanarPoint( normal, mirrorWorldPosition ); 248 mirrorPlane.applyMatrix4( mirrorCamera.matrixWorldInverse ); 249 clipPlane.set( mirrorPlane.normal.x, mirrorPlane.normal.y, mirrorPlane.normal.z, mirrorPlane.constant ); 250 const projectionMatrix = mirrorCamera.projectionMatrix; 251 q.x = ( Math.sign( clipPlane.x ) + projectionMatrix.elements[ 8 ] ) / projectionMatrix.elements[ 0 ]; 252 q.y = ( Math.sign( clipPlane.y ) + projectionMatrix.elements[ 9 ] ) / projectionMatrix.elements[ 5 ]; 253 q.z = - 1.0; 254 q.w = ( 1.0 + projectionMatrix.elements[ 10 ] ) / projectionMatrix.elements[ 14 ]; // Calculate the scaled plane vector 255 256 clipPlane.multiplyScalar( 2.0 / clipPlane.dot( q ) ); // Replacing the third row of the projection matrix 257 258 projectionMatrix.elements[ 2 ] = clipPlane.x; 259 projectionMatrix.elements[ 6 ] = clipPlane.y; 260 projectionMatrix.elements[ 10 ] = clipPlane.z + 1.0 - clipBias; 261 projectionMatrix.elements[ 14 ] = clipPlane.w; 262 eye.setFromMatrixPosition( camera.matrixWorld ); // Render 263 264 const currentRenderTarget = renderer.getRenderTarget(); 265 const currentXrEnabled = renderer.xr.enabled; 266 const currentShadowAutoUpdate = renderer.shadowMap.autoUpdate; 267 scope.visible = false;
268 renderer.xr.enabled = false; // Avoid camera modification and recursion 269 270 renderer.shadowMap.autoUpdate = false; // Avoid re-computing shadows 271 272 renderer.setRenderTarget( renderTarget ); 273 renderer.state.buffers.depth.setMask( true ); // make sure the depth buffer is writable so it can be properly cleared, see #18897 274 275 if ( renderer.autoClear === false ) renderer.clear(); 276 renderer.render( scene, mirrorCamera ); 277 scope.visible = true; 278 renderer.xr.enabled = currentXrEnabled; 279 renderer.shadowMap.autoUpdate = currentShadowAutoUpdate; 280 renderer.setRenderTarget( currentRenderTarget ); // Restore viewport 281 282 const viewport = camera.viewport; 283 284 if ( viewport !== undefined ) { 285 286 renderer.state.viewport( viewport ); 287 288 } 289 290 }; 291 292 } 293 294 } 295 296 Water.prototype.isWater = true; 297 298 THREE.Water = Water; 299 300} )();
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.