Ver código fonte

Parallax mapping example

Jan Wrobel 10 anos atrás
pai
commit
ab675778a8

+ 1 - 0
examples/index.html

@@ -215,6 +215,7 @@
 				"webgl_materials_lightmap",
 				"webgl_materials_normalmap",
 				"webgl_materials_normalmap2",
+				"webgl_materials_parallaxmap",
 				"webgl_materials_shaders_fresnel",
 				"webgl_materials_skin",
 				"webgl_materials_texture_anisotropy",

+ 182 - 0
examples/js/shaders/ParallaxShader.js

@@ -0,0 +1,182 @@
+// 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": { type: "t", value: null },
+		"map": { type: "t", value: null },
+		"parallaxScale": { type: "f", value: null },
+		"parallaxMinLayers": { type: "f", value: null },
+		"parallaxMaxLayers": { type: "f", 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 )
+				"for ( int i = 0; i == 0; i += 0 ) {",
+					"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" )
+
+};

BIN
examples/textures/brick_bump.jpg


BIN
examples/textures/brick_diffuse.jpg


+ 180 - 0
examples/webgl_materials_parallaxmap.html

@@ -0,0 +1,180 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - parallax mapping</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<style>
+			body {
+				background:#000;
+				color:#fff;
+				padding:0;
+				margin:0;
+				font-weight: bold;
+				overflow:hidden;
+			}
+
+			a {	color: #ffffff;	}
+
+			#info {
+				position: absolute;
+				top: 0px; width: 100%;
+				color: #ffffff;
+				padding: 5px;
+				font-family:Monospace;
+				font-size:10px;
+				text-align:center;
+			}
+
+			#oldie {
+				background:rgb(200,100,0) !important;
+				color:#fff;
+			}
+
+			#vt { display:none }
+			#vt, #vt a { color:orange; }
+		</style>
+	</head>
+
+	<body>
+
+		<div id="info">
+			<a href="http://threejs.org">Three.js</a> parallax mapping <br />
+			Oryginal shaders authors:
+			<a href="http://sunandblackcat.com/tipFullView.php?topicid=28">Igor Dyhta</a>,
+			<a href="http://mmikkelsen3d.blogspot.sk/2012/02/parallaxpoc-mapping-and-no-tangent.html">Morten S. Mikkelsen</a><br />
+			Texture by <a href="http://agf81.deviantart.com/">AGF81</a>
+		</div>
+
+		<script src="../build/three.min.js"></script>
+		<script src="js/Detector.js"></script>
+		<script src="js/libs/dat.gui.min.js"></script>
+		<script src="js/libs/stats.min.js"></script>
+
+		<script src="js/controls/OrbitControls.js"></script>
+
+		<script src="js/shaders/ParallaxShader.js"></script>
+
+		<script>
+			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
+
+			var stats;
+			var camera, scene, material, renderer;
+
+			var effectController = {
+				'mode': 'relief',
+				'scale': 0.005,
+				'minLayers': 20,
+				'maxLayers': 25,
+			};
+
+			init();
+			initGUI();
+			animate();
+
+			function init() {
+
+				var container = document.createElement( 'div' );
+				document.body.appendChild( container );
+
+				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.01, 10 );
+				camera.position.z = 2;
+				scene = new THREE.Scene();
+
+				initScene();
+
+				renderer = new THREE.WebGLRenderer( { antialias: true } );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				container.appendChild( renderer.domElement );
+
+				renderer.gammaInput = true;
+				renderer.gammaOutput = true;
+
+				var controls = new THREE.OrbitControls( camera, renderer.domElement );
+
+				stats = new Stats();
+				stats.domElement.style.position = 'absolute';
+				stats.domElement.style.top = '0px';
+				stats.domElement.style.zIndex = 100;
+				container.appendChild( stats.domElement );
+
+				window.addEventListener( 'resize', onWindowResize, false );
+
+			}
+
+			function guiChanged() {
+
+				var uniforms = material.uniforms;
+
+				uniforms[ 'parallaxScale' ].value = -1.0 * effectController.scale;
+				uniforms[ 'parallaxMinLayers' ].value = effectController.minLayers;
+				uniforms[ 'parallaxMaxLayers' ].value = effectController.maxLayers;
+
+				material.defines = {};
+				material.defines[THREE.ParallaxShader.modes[effectController.mode]] = '';
+				material.needsUpdate = true;
+
+			}
+
+			function initGUI() {
+
+				var gui = new dat.GUI();
+
+				gui.add( effectController, 'mode', Object.keys( THREE.ParallaxShader.modes ) ).onChange( guiChanged );
+				gui.add( effectController, 'scale', 0.0, 0.01, 0.001 ).onChange( guiChanged );
+				gui.add( effectController, 'minLayers', 1.0, 30, 1 ).onChange( guiChanged );
+				gui.add( effectController, 'maxLayers', 1.0, 30, 1 ).onChange( guiChanged );
+
+				guiChanged();
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+			function initScene() {
+
+				var shader = THREE.ParallaxShader;
+				var uniforms = THREE.UniformsUtils.clone( shader.uniforms );
+				var parameters = {
+					fragmentShader: shader.fragmentShader,
+					vertexShader: shader.vertexShader,
+					uniforms: uniforms
+				};
+				material = new THREE.ShaderMaterial( parameters );
+				material.map = THREE.ImageUtils.loadTexture( 'textures/brick_diffuse.jpg' );
+				material.bumpMap = THREE.ImageUtils.loadTexture( 'textures/brick_bump.jpg' );
+				material.map.anisotropy = 4;
+				material.bumpMap.anisotropy = 4;
+				uniforms[ 'map' ].value = material.map;
+				uniforms[ 'bumpMap' ].value = material.bumpMap;
+
+				var geometry = new THREE.CubeGeometry( 1.0, 1.0, 1.0 );
+				var mesh = new THREE.Mesh( geometry, material );
+				scene.add( mesh );
+
+			}
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				render();
+				stats.update();
+
+			}
+
+			function render() {
+
+				renderer.render( scene, camera );
+
+			}
+		</script>
+
+	</body>
+</html>