ParallaxShader.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. ( function () {
  2. // Parallax Occlusion shaders from
  3. // http://sunandblackcat.com/tipFullView.php?topicid=28
  4. // No tangent-space transforms logic based on
  5. // http://mmikkelsen3d.blogspot.sk/2012/02/parallaxpoc-mapping-and-no-tangent.html
  6. const ParallaxShader = {
  7. // Ordered from fastest to best quality.
  8. modes: {
  9. none: 'NO_PARALLAX',
  10. basic: 'USE_BASIC_PARALLAX',
  11. steep: 'USE_STEEP_PARALLAX',
  12. occlusion: 'USE_OCLUSION_PARALLAX',
  13. // a.k.a. POM
  14. relief: 'USE_RELIEF_PARALLAX'
  15. },
  16. uniforms: {
  17. 'bumpMap': {
  18. value: null
  19. },
  20. 'map': {
  21. value: null
  22. },
  23. 'parallaxScale': {
  24. value: null
  25. },
  26. 'parallaxMinLayers': {
  27. value: null
  28. },
  29. 'parallaxMaxLayers': {
  30. value: null
  31. }
  32. },
  33. vertexShader:
  34. /* glsl */
  35. `
  36. varying vec2 vUv;
  37. varying vec3 vViewPosition;
  38. varying vec3 vNormal;
  39. void main() {
  40. vUv = uv;
  41. vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
  42. vViewPosition = -mvPosition.xyz;
  43. vNormal = normalize( normalMatrix * normal );
  44. gl_Position = projectionMatrix * mvPosition;
  45. }`,
  46. fragmentShader:
  47. /* glsl */
  48. `
  49. uniform sampler2D bumpMap;
  50. uniform sampler2D map;
  51. uniform float parallaxScale;
  52. uniform float parallaxMinLayers;
  53. uniform float parallaxMaxLayers;
  54. varying vec2 vUv;
  55. varying vec3 vViewPosition;
  56. varying vec3 vNormal;
  57. #ifdef USE_BASIC_PARALLAX
  58. vec2 parallaxMap( in vec3 V ) {
  59. float initialHeight = texture2D( bumpMap, vUv ).r;
  60. // No Offset Limitting: messy, floating output at grazing angles.
  61. //"vec2 texCoordOffset = parallaxScale * V.xy / V.z * initialHeight;",
  62. // Offset Limiting
  63. vec2 texCoordOffset = parallaxScale * V.xy * initialHeight;
  64. return vUv - texCoordOffset;
  65. }
  66. #else
  67. vec2 parallaxMap( in vec3 V ) {
  68. // Determine number of layers from angle between V and N
  69. float numLayers = mix( parallaxMaxLayers, parallaxMinLayers, abs( dot( vec3( 0.0, 0.0, 1.0 ), V ) ) );
  70. float layerHeight = 1.0 / numLayers;
  71. float currentLayerHeight = 0.0;
  72. // Shift of texture coordinates for each iteration
  73. vec2 dtex = parallaxScale * V.xy / V.z / numLayers;
  74. vec2 currentTextureCoords = vUv;
  75. float heightFromTexture = texture2D( bumpMap, currentTextureCoords ).r;
  76. // while ( heightFromTexture > currentLayerHeight )
  77. // Infinite loops are not well supported. Do a "large" finite
  78. // loop, but not too large, as it slows down some compilers.
  79. for ( int i = 0; i < 30; i += 1 ) {
  80. if ( heightFromTexture <= currentLayerHeight ) {
  81. break;
  82. }
  83. currentLayerHeight += layerHeight;
  84. // Shift texture coordinates along vector V
  85. currentTextureCoords -= dtex;
  86. heightFromTexture = texture2D( bumpMap, currentTextureCoords ).r;
  87. }
  88. #ifdef USE_STEEP_PARALLAX
  89. return currentTextureCoords;
  90. #elif defined( USE_RELIEF_PARALLAX )
  91. vec2 deltaTexCoord = dtex / 2.0;
  92. float deltaHeight = layerHeight / 2.0;
  93. // Return to the mid point of previous layer
  94. currentTextureCoords += deltaTexCoord;
  95. currentLayerHeight -= deltaHeight;
  96. // Binary search to increase precision of Steep Parallax Mapping
  97. const int numSearches = 5;
  98. for ( int i = 0; i < numSearches; i += 1 ) {
  99. deltaTexCoord /= 2.0;
  100. deltaHeight /= 2.0;
  101. heightFromTexture = texture2D( bumpMap, currentTextureCoords ).r;
  102. // Shift along or against vector V
  103. if( heightFromTexture > currentLayerHeight ) { // Below the surface
  104. currentTextureCoords -= deltaTexCoord;
  105. currentLayerHeight += deltaHeight;
  106. } else { // above the surface
  107. currentTextureCoords += deltaTexCoord;
  108. currentLayerHeight -= deltaHeight;
  109. }
  110. }
  111. return currentTextureCoords;
  112. #elif defined( USE_OCLUSION_PARALLAX )
  113. vec2 prevTCoords = currentTextureCoords + dtex;
  114. // Heights for linear interpolation
  115. float nextH = heightFromTexture - currentLayerHeight;
  116. float prevH = texture2D( bumpMap, prevTCoords ).r - currentLayerHeight + layerHeight;
  117. // Proportions for linear interpolation
  118. float weight = nextH / ( nextH - prevH );
  119. // Interpolation of texture coordinates
  120. return prevTCoords * weight + currentTextureCoords * ( 1.0 - weight );
  121. #else // NO_PARALLAX
  122. return vUv;
  123. #endif
  124. }
  125. #endif
  126. vec2 perturbUv( vec3 surfPosition, vec3 surfNormal, vec3 viewPosition ) {
  127. vec2 texDx = dFdx( vUv );
  128. vec2 texDy = dFdy( vUv );
  129. vec3 vSigmaX = dFdx( surfPosition );
  130. vec3 vSigmaY = dFdy( surfPosition );
  131. vec3 vR1 = cross( vSigmaY, surfNormal );
  132. vec3 vR2 = cross( surfNormal, vSigmaX );
  133. float fDet = dot( vSigmaX, vR1 );
  134. vec2 vProjVscr = ( 1.0 / fDet ) * vec2( dot( vR1, viewPosition ), dot( vR2, viewPosition ) );
  135. vec3 vProjVtex;
  136. vProjVtex.xy = texDx * vProjVscr.x + texDy * vProjVscr.y;
  137. vProjVtex.z = dot( surfNormal, viewPosition );
  138. return parallaxMap( vProjVtex );
  139. }
  140. void main() {
  141. vec2 mapUv = perturbUv( -vViewPosition, normalize( vNormal ), normalize( vViewPosition ) );
  142. gl_FragColor = texture2D( map, mapUv );
  143. }`
  144. };
  145. THREE.ParallaxShader = ParallaxShader;
  146. } )();