ts/public/GV/thirdParty/Threejs-109/examples/js/shaders/ParallaxShader.js
2024-12-09 14:44:52 +08:00

185 lines
5.3 KiB
JavaScript

// Parallax Occlusion shaders from
// http://sunandblackcat.com/tipFullView.php?topicid=28
// No tangent-space transforms logic based on
// http://mmikkelsen3d.blogspot.sk/2012/02/parallaxpoc-mapping-and-no-tangent.html
THREE.ParallaxShader = {
// Ordered from fastest to best quality.
modes: {
none: "NO_PARALLAX",
basic: "USE_BASIC_PARALLAX",
steep: "USE_STEEP_PARALLAX",
occlusion: "USE_OCLUSION_PARALLAX", // a.k.a. POM
relief: "USE_RELIEF_PARALLAX"
},
uniforms: {
"bumpMap": { value: null },
"map": { value: null },
"parallaxScale": { value: null },
"parallaxMinLayers": { value: null },
"parallaxMaxLayers": { value: null }
},
vertexShader: [
"varying vec2 vUv;",
"varying vec3 vViewPosition;",
"varying vec3 vNormal;",
"void main() {",
" vUv = uv;",
" vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
" vViewPosition = -mvPosition.xyz;",
" vNormal = normalize( normalMatrix * normal );",
" gl_Position = projectionMatrix * mvPosition;",
"}"
].join( "\n" ),
fragmentShader: [
"uniform sampler2D bumpMap;",
"uniform sampler2D map;",
"uniform float parallaxScale;",
"uniform float parallaxMinLayers;",
"uniform float parallaxMaxLayers;",
"varying vec2 vUv;",
"varying vec3 vViewPosition;",
"varying vec3 vNormal;",
"#ifdef USE_BASIC_PARALLAX",
" vec2 parallaxMap( in vec3 V ) {",
" float initialHeight = texture2D( bumpMap, vUv ).r;",
// No Offset Limitting: messy, floating output at grazing angles.
//"vec2 texCoordOffset = parallaxScale * V.xy / V.z * initialHeight;",
// Offset Limiting
" vec2 texCoordOffset = parallaxScale * V.xy * initialHeight;",
" return vUv - texCoordOffset;",
" }",
"#else",
" vec2 parallaxMap( in vec3 V ) {",
// Determine number of layers from angle between V and N
" float numLayers = mix( parallaxMaxLayers, parallaxMinLayers, abs( dot( vec3( 0.0, 0.0, 1.0 ), V ) ) );",
" float layerHeight = 1.0 / numLayers;",
" float currentLayerHeight = 0.0;",
// Shift of texture coordinates for each iteration
" vec2 dtex = parallaxScale * V.xy / V.z / numLayers;",
" vec2 currentTextureCoords = vUv;",
" float heightFromTexture = texture2D( bumpMap, currentTextureCoords ).r;",
// while ( heightFromTexture > currentLayerHeight )
// Infinite loops are not well supported. Do a "large" finite
// loop, but not too large, as it slows down some compilers.
" for ( int i = 0; i < 30; i += 1 ) {",
" if ( heightFromTexture <= currentLayerHeight ) {",
" break;",
" }",
" currentLayerHeight += layerHeight;",
// Shift texture coordinates along vector V
" currentTextureCoords -= dtex;",
" heightFromTexture = texture2D( bumpMap, currentTextureCoords ).r;",
" }",
" #ifdef USE_STEEP_PARALLAX",
" return currentTextureCoords;",
" #elif defined( USE_RELIEF_PARALLAX )",
" vec2 deltaTexCoord = dtex / 2.0;",
" float deltaHeight = layerHeight / 2.0;",
// Return to the mid point of previous layer
" currentTextureCoords += deltaTexCoord;",
" currentLayerHeight -= deltaHeight;",
// Binary search to increase precision of Steep Parallax Mapping
" const int numSearches = 5;",
" for ( int i = 0; i < numSearches; i += 1 ) {",
" deltaTexCoord /= 2.0;",
" deltaHeight /= 2.0;",
" heightFromTexture = texture2D( bumpMap, currentTextureCoords ).r;",
// Shift along or against vector V
" if( heightFromTexture > currentLayerHeight ) {", // Below the surface
" currentTextureCoords -= deltaTexCoord;",
" currentLayerHeight += deltaHeight;",
" } else {", // above the surface
" currentTextureCoords += deltaTexCoord;",
" currentLayerHeight -= deltaHeight;",
" }",
" }",
" return currentTextureCoords;",
" #elif defined( USE_OCLUSION_PARALLAX )",
" vec2 prevTCoords = currentTextureCoords + dtex;",
// Heights for linear interpolation
" float nextH = heightFromTexture - currentLayerHeight;",
" float prevH = texture2D( bumpMap, prevTCoords ).r - currentLayerHeight + layerHeight;",
// Proportions for linear interpolation
" float weight = nextH / ( nextH - prevH );",
// Interpolation of texture coordinates
" return prevTCoords * weight + currentTextureCoords * ( 1.0 - weight );",
" #else", // NO_PARALLAX
" return vUv;",
" #endif",
" }",
"#endif",
"vec2 perturbUv( vec3 surfPosition, vec3 surfNormal, vec3 viewPosition ) {",
" vec2 texDx = dFdx( vUv );",
" vec2 texDy = dFdy( vUv );",
" vec3 vSigmaX = dFdx( surfPosition );",
" vec3 vSigmaY = dFdy( surfPosition );",
" vec3 vR1 = cross( vSigmaY, surfNormal );",
" vec3 vR2 = cross( surfNormal, vSigmaX );",
" float fDet = dot( vSigmaX, vR1 );",
" vec2 vProjVscr = ( 1.0 / fDet ) * vec2( dot( vR1, viewPosition ), dot( vR2, viewPosition ) );",
" vec3 vProjVtex;",
" vProjVtex.xy = texDx * vProjVscr.x + texDy * vProjVscr.y;",
" vProjVtex.z = dot( surfNormal, viewPosition );",
" return parallaxMap( vProjVtex );",
"}",
"void main() {",
" vec2 mapUv = perturbUv( -vViewPosition, normalize( vNormal ), normalize( vViewPosition ) );",
" gl_FragColor = texture2D( map, mapUv );",
"}"
].join( "\n" )
};