ParallaxShader.js 5.2 KB

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