parallax mapping

by sogrey

HTML

<script src="https://threejs.org/build/three.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

CSS

body { margin: 0; position: fixed; }
canvas { width: 100%; height: 100%; display: block; }

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

var 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...