three-stdlib
Version:
stand-alone library of threejs examples
185 lines (137 loc) • 5.08 kB
JavaScript
const 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: (
/* glsl */
`
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;
}
`
),
fragmentShader: (
/* glsl */
`
uniform sampler2D bumpMap;
uniform sampler2D map;
uniform float parallaxScale;
uniform float parallaxMinLayers;
uniform float parallaxMaxLayers;
varying vec2 vUv;
varying vec3 vViewPosition;
varying vec3 vNormal;
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;
}
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;
}
return currentTextureCoords;
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;
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 );
return vUv;
}
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 );
}
`
)
};
export {
ParallaxShader
};
//# sourceMappingURL=ParallaxShader.js.map