浏览代码

Add example for gpu-assisted picking

Dylan Halperin 13 年之前
父节点
当前提交
0715dd3eb3
共有 1 个文件被更改,包括 241 次插入0 次删除
  1. 241 0
      examples/webgl_gpu_picking.html

+ 241 - 0
examples/webgl_gpu_picking.html

@@ -0,0 +1,241 @@
+<!doctype html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - gpu picking</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 {
+				font-family: Monospace;
+				background-color: #f0f0f0;
+				margin: 0px;
+				overflow: hidden;
+			}
+			
+			.info {
+				position: absolute;
+				background-color: black;
+				opacity: 0.8;
+				color: white;
+				text-align: center;
+				top: 0px;
+				width: 100%;
+			}
+			
+			.info a {
+				color: #00ffff;
+			}
+		</style>
+	</head>
+	<body>
+
+		<div class="info">
+			<a href="http://github.com/mrdoob/three.js" target="_blank">three.js</a> webgl - gpu picking
+		</div>
+		
+		<div id="container"></div>
+	
+		<script src="../build/Three.js"></script>
+
+		<script src="js/Stats.js"></script>
+
+		<script>
+
+			var container, stats;
+			var camera, controls, scene, renderer;
+			var pickingData = [], pickingTexture, pickingScene;
+			var objects = [];
+			var highlightBox;
+
+			var mouse = new THREE.Vector2(),
+				offset = new THREE.Vector3(10, 10, 10);
+
+			init();
+			animate();
+
+			function init() {
+
+				container = document.getElementById("container");
+
+				scene = new THREE.Scene();
+				pickingScene = new THREE.Scene();
+				pickingTexture = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight);
+				pickingTexture.generateMipmaps = false;
+
+				camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 10000 );
+				camera.position.z = 1000;
+				scene.add( camera );
+
+				controls = new THREE.TrackballControls( camera );
+				controls.rotateSpeed = 1.0;
+				controls.zoomSpeed = 1.2;
+				controls.panSpeed = 0.8;
+				controls.noZoom = false;
+				controls.noPan = false;
+				controls.staticMoving = true;
+				controls.dynamicDampingFactor = 0.3;
+
+				scene.add( new THREE.AmbientLight( 0x555555 ) );
+
+				var light = new THREE.SpotLight( 0xffffff, 1.5 );
+				
+				light.position.set( 0, 500, 2000 );
+				light.castShadow = true;
+
+				light.shadowCameraNear = 200;
+				light.shadowCameraFar = camera.far;
+				light.shadowCameraFov = 50;
+
+				light.shadowBias = -0.00022;
+				light.shadowDarkness = 0.5;
+
+				light.shadowMapWidth = 1024;
+				light.shadowMapHeight = 1024;
+
+				scene.add( light );
+
+				var geometry = new THREE.Geometry(),
+					pickingGeometry = new THREE.Geometry(),
+					pickingMaterial = new THREE.MeshBasicMaterial({
+						vertexColors: THREE.VertexColors
+					}),
+					defaultMaterial = new THREE.MeshLambertMaterial({
+						color: 0xffffff,
+						shading: THREE.FlatShading,
+						vertexColors: THREE.VertexColors
+					});
+
+				function applyVertexColors(g, c) {
+					g.faces.forEach(function(f){
+						var n = (f instanceof THREE.Face3) ? 3 : 4;
+						for(var j=0; j<n; j++){
+							f.vertexColors[j] = c;
+						}
+					});
+				}
+				
+				for ( var i = 0; i < 5000; i ++ ) {
+					var position = new THREE.Vector3();
+					position.x = Math.random() * 10000 - 5000;
+					position.y = Math.random() * 6000 - 3000;
+					position.z = Math.random() * 8000 - 4000;
+
+					var rotation = new THREE.Vector3();
+					rotation.x = ( Math.random() * 2 * Math.PI);
+					rotation.y = ( Math.random() * 2 * Math.PI);
+					rotation.z = ( Math.random() * 2 * Math.PI);
+
+					var scale = new THREE.Vector3();
+					scale.x = Math.random() * 200 + 100;
+					scale.y = Math.random() * 200 + 100;
+					scale.z = Math.random() * 200 + 100;
+					
+					//give the geom's vertices a random color, to be displayed
+					var geom = new THREE.CubeGeometry(1, 1, 1);
+					var color = new THREE.Color(Math.random() * 0xffffff);
+					applyVertexColors(geom, color);
+					var cube = new THREE.Mesh(geom);
+					cube.position.copy(position);
+					cube.rotation.copy(rotation);
+					cube.scale.copy(scale);
+					THREE.GeometryUtils.merge(geometry, cube);
+
+					//give the pickingGeom's vertices a color corresponding to the "id"
+					var pickingGeom = new THREE.CubeGeometry(1, 1, 1);
+					var pickingColor = new THREE.Color(i);
+					applyVertexColors(pickingGeom, pickingColor);
+					var pickingCube = new THREE.Mesh(pickingGeom);
+					pickingCube.position.copy(position);
+					pickingCube.rotation.copy(rotation);
+					pickingCube.scale.copy(scale);
+					THREE.GeometryUtils.merge(pickingGeometry, pickingCube);
+
+					pickingData[i] = {
+						position: position,
+						rotation: rotation,
+						scale: scale
+					};
+				}
+				var drawnObject = new THREE.Mesh(geometry, defaultMaterial);
+					//drawnObject.castShadow = true;
+					//drawnObject.receiveShadow = true;
+					scene.add(drawnObject);
+					
+				pickingScene.add(new THREE.Mesh(pickingGeometry, pickingMaterial));
+
+				highlightBox = new THREE.Mesh(new THREE.CubeGeometry(1, 1, 1), new THREE.MeshLambertMaterial({color: 0xffff00}));
+				scene.add(highlightBox);
+				
+				projector = new THREE.Projector();
+
+				renderer = new THREE.WebGLRenderer( { antialias: true, clearColor: 0xffffff } );
+				renderer.sortObjects = false;
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+				renderer.shadowMapEnabled = true;
+				renderer.shadowMapSoft = true;
+
+				container.appendChild( renderer.domElement );
+				
+				stats = new Stats();
+				stats.domElement.style.position = 'absolute';
+				stats.domElement.style.top = '0px';
+				container.appendChild( stats.domElement );
+				
+				renderer.domElement.addEventListener('mousemove', onMouseMove);
+			}
+			//
+
+			function onMouseMove(e) {
+				mouse.x = e.clientX;
+				mouse.y = e.clientY;
+			}
+			
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				render();
+				stats.update();
+
+			}
+
+			function pick() {
+				//render the picking scene off-screen
+				var gl = self.renderer.getContext();
+				renderer.render(pickingScene, camera, pickingTexture);
+				var pixelBuffer = new Uint8Array(4);
+				
+				//read the pixel under the mouse from the texture
+				gl.readPixels(mouse.x, pickingTexture.height - mouse.y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixelBuffer);
+				
+				//interpret the pixel as an ID
+				var id = (pixelBuffer[0] << 16) | (pixelBuffer[1] << 8) | (pixelBuffer[2]);
+				var data = pickingData[id];
+				if(data){
+					//move our highlightBox so that it surrounds the picked object
+					if(data.position && data.rotation && data.scale){
+						highlightBox.position.copy(data.position);
+						highlightBox.rotation.copy(data.rotation);
+						highlightBox.scale.copy(data.scale).addSelf(offset);
+						highlightBox.visible = true;
+					}
+				} else {
+					highlightBox.visible = false;
+				}
+			}
+			
+			function render() {
+
+				controls.update();
+
+				pick();
+
+				renderer.render( scene, camera );
+
+			}
+
+		</script>
+
+	</body>
+</html>