Water2.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /**
  2. * @author Mugen87 / https://github.com/Mugen87
  3. *
  4. * References:
  5. * http://www.valvesoftware.com/publications/2010/siggraph2010_vlachos_waterflow.pdf
  6. * http://graphicsrunner.blogspot.de/2010/08/water-using-flow-maps.html
  7. *
  8. */
  9. import {
  10. Clock,
  11. Color,
  12. Matrix4,
  13. Mesh,
  14. RepeatWrapping,
  15. ShaderMaterial,
  16. TextureLoader,
  17. UniformsLib,
  18. UniformsUtils,
  19. Vector2,
  20. Vector4
  21. } from "../../../build/three.module.js";
  22. import { Reflector } from "../objects/Reflector.js";
  23. import { Refractor } from "../objects/Refractor.js";
  24. var Water = function ( geometry, options ) {
  25. Mesh.call( this, geometry );
  26. this.type = 'Water';
  27. var scope = this;
  28. options = options || {};
  29. var color = ( options.color !== undefined ) ? new Color( options.color ) : new Color( 0xFFFFFF );
  30. var textureWidth = options.textureWidth || 512;
  31. var textureHeight = options.textureHeight || 512;
  32. var clipBias = options.clipBias || 0;
  33. var flowDirection = options.flowDirection || new Vector2( 1, 0 );
  34. var flowSpeed = options.flowSpeed || 0.03;
  35. var reflectivity = options.reflectivity || 0.02;
  36. var scale = options.scale || 1;
  37. var shader = options.shader || Water.WaterShader;
  38. var textureLoader = new TextureLoader();
  39. var flowMap = options.flowMap || undefined;
  40. var normalMap0 = options.normalMap0 || textureLoader.load( 'textures/water/Water_1_M_Normal.jpg' );
  41. var normalMap1 = options.normalMap1 || textureLoader.load( 'textures/water/Water_2_M_Normal.jpg' );
  42. var cycle = 0.15; // a cycle of a flow map phase
  43. var halfCycle = cycle * 0.5;
  44. var textureMatrix = new Matrix4();
  45. var clock = new Clock();
  46. // internal components
  47. if ( Reflector === undefined ) {
  48. console.error( 'THREE.Water: Required component Reflector not found.' );
  49. return;
  50. }
  51. if ( Refractor === undefined ) {
  52. console.error( 'THREE.Water: Required component Refractor not found.' );
  53. return;
  54. }
  55. var reflector = new Reflector( geometry, {
  56. textureWidth: textureWidth,
  57. textureHeight: textureHeight,
  58. clipBias: clipBias
  59. } );
  60. var refractor = new Refractor( geometry, {
  61. textureWidth: textureWidth,
  62. textureHeight: textureHeight,
  63. clipBias: clipBias
  64. } );
  65. reflector.matrixAutoUpdate = false;
  66. refractor.matrixAutoUpdate = false;
  67. // material
  68. this.material = new ShaderMaterial( {
  69. uniforms: UniformsUtils.merge( [
  70. UniformsLib[ 'fog' ],
  71. shader.uniforms
  72. ] ),
  73. vertexShader: shader.vertexShader,
  74. fragmentShader: shader.fragmentShader,
  75. transparent: true,
  76. fog: true
  77. } );
  78. if ( flowMap !== undefined ) {
  79. this.material.defines.USE_FLOWMAP = '';
  80. this.material.uniforms[ "tFlowMap" ] = {
  81. type: 't',
  82. value: flowMap
  83. };
  84. } else {
  85. this.material.uniforms[ "flowDirection" ] = {
  86. type: 'v2',
  87. value: flowDirection
  88. };
  89. }
  90. // maps
  91. normalMap0.wrapS = normalMap0.wrapT = RepeatWrapping;
  92. normalMap1.wrapS = normalMap1.wrapT = RepeatWrapping;
  93. this.material.uniforms[ "tReflectionMap" ].value = reflector.getRenderTarget().texture;
  94. this.material.uniforms[ "tRefractionMap" ].value = refractor.getRenderTarget().texture;
  95. this.material.uniforms[ "tNormalMap0" ].value = normalMap0;
  96. this.material.uniforms[ "tNormalMap1" ].value = normalMap1;
  97. // water
  98. this.material.uniforms[ "color" ].value = color;
  99. this.material.uniforms[ "reflectivity" ].value = reflectivity;
  100. this.material.uniforms[ "textureMatrix" ].value = textureMatrix;
  101. // inital values
  102. this.material.uniforms[ "config" ].value.x = 0; // flowMapOffset0
  103. this.material.uniforms[ "config" ].value.y = halfCycle; // flowMapOffset1
  104. this.material.uniforms[ "config" ].value.z = halfCycle; // halfCycle
  105. this.material.uniforms[ "config" ].value.w = scale; // scale
  106. // functions
  107. function updateTextureMatrix( camera ) {
  108. textureMatrix.set(
  109. 0.5, 0.0, 0.0, 0.5,
  110. 0.0, 0.5, 0.0, 0.5,
  111. 0.0, 0.0, 0.5, 0.5,
  112. 0.0, 0.0, 0.0, 1.0
  113. );
  114. textureMatrix.multiply( camera.projectionMatrix );
  115. textureMatrix.multiply( camera.matrixWorldInverse );
  116. textureMatrix.multiply( scope.matrixWorld );
  117. }
  118. function updateFlow() {
  119. var delta = clock.getDelta();
  120. var config = scope.material.uniforms[ "config" ];
  121. config.value.x += flowSpeed * delta; // flowMapOffset0
  122. config.value.y = config.value.x + halfCycle; // flowMapOffset1
  123. // Important: The distance between offsets should be always the value of "halfCycle".
  124. // Moreover, both offsets should be in the range of [ 0, cycle ].
  125. // This approach ensures a smooth water flow and avoids "reset" effects.
  126. if ( config.value.x >= cycle ) {
  127. config.value.x = 0;
  128. config.value.y = halfCycle;
  129. } else if ( config.value.y >= cycle ) {
  130. config.value.y = config.value.y - cycle;
  131. }
  132. }
  133. //
  134. this.onBeforeRender = function ( renderer, scene, camera ) {
  135. updateTextureMatrix( camera );
  136. updateFlow();
  137. scope.visible = false;
  138. reflector.matrixWorld.copy( scope.matrixWorld );
  139. refractor.matrixWorld.copy( scope.matrixWorld );
  140. reflector.onBeforeRender( renderer, scene, camera );
  141. refractor.onBeforeRender( renderer, scene, camera );
  142. scope.visible = true;
  143. };
  144. };
  145. Water.prototype = Object.create( Mesh.prototype );
  146. Water.prototype.constructor = Water;
  147. Water.WaterShader = {
  148. uniforms: {
  149. 'color': {
  150. type: 'c',
  151. value: null
  152. },
  153. 'reflectivity': {
  154. type: 'f',
  155. value: 0
  156. },
  157. 'tReflectionMap': {
  158. type: 't',
  159. value: null
  160. },
  161. 'tRefractionMap': {
  162. type: 't',
  163. value: null
  164. },
  165. 'tNormalMap0': {
  166. type: 't',
  167. value: null
  168. },
  169. 'tNormalMap1': {
  170. type: 't',
  171. value: null
  172. },
  173. 'textureMatrix': {
  174. type: 'm4',
  175. value: null
  176. },
  177. 'config': {
  178. type: 'v4',
  179. value: new Vector4()
  180. }
  181. },
  182. vertexShader: [
  183. '#include <fog_pars_vertex>',
  184. '#include <logdepthbuf_pars_vertex>',
  185. 'uniform mat4 textureMatrix;',
  186. 'varying vec4 vCoord;',
  187. 'varying vec2 vUv;',
  188. 'varying vec3 vToEye;',
  189. 'void main() {',
  190. ' vUv = uv;',
  191. ' vCoord = textureMatrix * vec4( position, 1.0 );',
  192. ' vec4 worldPosition = modelMatrix * vec4( position, 1.0 );',
  193. ' vToEye = cameraPosition - worldPosition.xyz;',
  194. ' vec4 mvPosition = viewMatrix * worldPosition;', // used in fog_vertex
  195. ' gl_Position = projectionMatrix * mvPosition;',
  196. ' #include <logdepthbuf_vertex>',
  197. ' #include <fog_vertex>',
  198. '}'
  199. ].join( '\n' ),
  200. fragmentShader: [
  201. '#include <common>',
  202. '#include <fog_pars_fragment>',
  203. '#include <logdepthbuf_pars_fragment>',
  204. 'uniform sampler2D tReflectionMap;',
  205. 'uniform sampler2D tRefractionMap;',
  206. 'uniform sampler2D tNormalMap0;',
  207. 'uniform sampler2D tNormalMap1;',
  208. '#ifdef USE_FLOWMAP',
  209. ' uniform sampler2D tFlowMap;',
  210. '#else',
  211. ' uniform vec2 flowDirection;',
  212. '#endif',
  213. 'uniform vec3 color;',
  214. 'uniform float reflectivity;',
  215. 'uniform vec4 config;',
  216. 'varying vec4 vCoord;',
  217. 'varying vec2 vUv;',
  218. 'varying vec3 vToEye;',
  219. 'void main() {',
  220. ' #include <logdepthbuf_fragment>',
  221. ' float flowMapOffset0 = config.x;',
  222. ' float flowMapOffset1 = config.y;',
  223. ' float halfCycle = config.z;',
  224. ' float scale = config.w;',
  225. ' vec3 toEye = normalize( vToEye );',
  226. // determine flow direction
  227. ' vec2 flow;',
  228. ' #ifdef USE_FLOWMAP',
  229. ' flow = texture2D( tFlowMap, vUv ).rg * 2.0 - 1.0;',
  230. ' #else',
  231. ' flow = flowDirection;',
  232. ' #endif',
  233. ' flow.x *= - 1.0;',
  234. // sample normal maps (distort uvs with flowdata)
  235. ' vec4 normalColor0 = texture2D( tNormalMap0, ( vUv * scale ) + flow * flowMapOffset0 );',
  236. ' vec4 normalColor1 = texture2D( tNormalMap1, ( vUv * scale ) + flow * flowMapOffset1 );',
  237. // linear interpolate to get the final normal color
  238. ' float flowLerp = abs( halfCycle - flowMapOffset0 ) / halfCycle;',
  239. ' vec4 normalColor = mix( normalColor0, normalColor1, flowLerp );',
  240. // calculate normal vector
  241. ' vec3 normal = normalize( vec3( normalColor.r * 2.0 - 1.0, normalColor.b, normalColor.g * 2.0 - 1.0 ) );',
  242. // calculate the fresnel term to blend reflection and refraction maps
  243. ' float theta = max( dot( toEye, normal ), 0.0 );',
  244. ' float reflectance = reflectivity + ( 1.0 - reflectivity ) * pow( ( 1.0 - theta ), 5.0 );',
  245. // calculate final uv coords
  246. ' vec3 coord = vCoord.xyz / vCoord.w;',
  247. ' vec2 uv = coord.xy + coord.z * normal.xz * 0.05;',
  248. ' vec4 reflectColor = texture2D( tReflectionMap, vec2( 1.0 - uv.x, uv.y ) );',
  249. ' vec4 refractColor = texture2D( tRefractionMap, uv );',
  250. // multiply water color with the mix of both textures
  251. ' gl_FragColor = vec4( color, 1.0 ) * mix( refractColor, reflectColor, reflectance );',
  252. ' #include <tonemapping_fragment>',
  253. ' #include <encodings_fragment>',
  254. ' #include <fog_fragment>',
  255. '}'
  256. ].join( '\n' )
  257. };
  258. export { Water };