ParallaxShader.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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. THREE.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. };