使用three.js制作可点击的粒子系统

时间:2016-09-14 15:31:53

标签: javascript three.js

我正在学习编写和玩three.js的第一步。从一段时间以前,我一直在寻找一种在three.js中制作交互式几何的方法。所以我发现这个(它不会打开代码片段中的链接,我不知道为什么,但它有效):

		var container, stats;
		var camera, scene, projector, renderer;
		var particleMaterial;
		var objects = [];
		init();
		animate();

		function init() {
    		container = document.createElement('div');
    		document.body.appendChild(container);
    		
    		camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 10000);
    		camera.position.set(0, 300, 500);
    
    		scene = new THREE.Scene();
    		
    		var geometry = new THREE.CubeGeometry(100, 100, 100);
    		
    		for (var i = 0; i < 4; i++) {
        		var object = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({
            	color: Math.random() * 0xffffff,
            	opacity: 0.5
        	}));
        	
        	object.position.x = i;
        	object.position.y = i * 10 + i * 100;
        	object.position.z = i;
        	scene.add(object);
        
        	switch (i) {
            	case 0:
                	object.userData = {
                    	URL: "http://google.com"
                	};
                break;
            
            	case 1:
                	object.userData = {
                    URL: "http://yahoo.com"
                };
                break;

            	case 2:
                	object.userData = {
                    URL: "http://msn.com"
                };
                break;
            
            	case 3:
                	object.userData = {
                    URL: "http://engadget.com"
                };
                break;

            	case 4:
                	object.userData = {
                    URL: "http://stackoverflow.com"
                };
                break;
        }

        scene.add(object);
        objects.push(object);
    }

    projector = new THREE.Projector();
    
    renderer = new THREE.CanvasRenderer();
    renderer.setClearColor(0xfffff, 0);
    renderer.setSize(window.innerWidth, window.innerHeight);
    container.appendChild(renderer.domElement);
   
    document.addEventListener('mousedown', onDocumentMouseDown, false);
    //
    window.addEventListener('resize', onWindowResize, false);
	}


function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
}

function onDocumentMouseDown(event) {
    
    event.preventDefault();
    
    var vector = new THREE.Vector3((event.clientX / window.innerWidth) * 2 - 1, -(event.clientY / window.innerHeight) * 2 + 1, 0.5);
    
    projector.unprojectVector(vector, camera);
    
    var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
    
    var intersects = raycaster.intersectObjects(objects);
    
    if (intersects.length > 0) {
        window.open(intersects[0].object.userData.URL);
    }
}

function animate() {
    
    requestAnimationFrame(animate);
    render();
   
}

function render() {
    renderer.render(scene, camera);
}
		<style>
			body {
				font-family: Monospace;
				background-color: #ffffff;
				margin: 0px;
				overflow: hidden;
			}
		</style>
<script src="http://threejs.org/build/three.min.js"></script>
<script src="http://threejs.org/examples/js/renderers/Projector.js"></script>
<script src="http://threejs.org/examples/js/renderers/CanvasRenderer.js"></script>

然后我想继续尝试并使其更难。所以我想做这个,而是使用立方体,使用粒子。我从这个Three.js演示中获得了灵感:

var mouseX = 0, mouseY = 0,

			windowHalfX = window.innerWidth / 2,
			windowHalfY = window.innerHeight / 2,

			SEPARATION = 200,
			AMOUNTX = 10,
			AMOUNTY = 10,

			camera, scene, renderer;

			init();
			animate();

			function init() {

				var container, separation = 100, amountX = 50, amountY = 50,
				particles, particle;

				container = document.createElement('div');
				document.body.appendChild(container);

				camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 );
				camera.position.z = 100;

				scene = new THREE.Scene();

				renderer = new THREE.CanvasRenderer();
				renderer.setPixelRatio( window.devicePixelRatio );
				renderer.setSize( window.innerWidth, window.innerHeight );
				container.appendChild( renderer.domElement );

				// particles

				var PI2 = Math.PI * 2;
				var material = new THREE.SpriteCanvasMaterial( {

					color: 0xffffff,
					program: function ( context ) {

						context.beginPath();
						context.arc( 0, 0, 0.5, 0, PI2, true );
						context.fill();

					}

				} );

				var geometry = new THREE.Geometry();

				for ( var i = 0; i < 100; i ++ ) {

					particle = new THREE.Sprite( material );
					particle.position.x = Math.random() * 2 - 1;
					particle.position.y = Math.random() * 2 - 1;
					particle.position.z = Math.random() * 2 - 1;
					particle.position.normalize();
					particle.position.multiplyScalar( Math.random() * 10 + 450 );
					particle.scale.x = particle.scale.y = 10;
					scene.add( particle );

					geometry.vertices.push( particle.position );

				}

				// lines

				var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0xffffff, opacity: 0.5 } ) );
				scene.add( line );

				document.addEventListener( 'mousemove', onDocumentMouseMove, false );
				document.addEventListener( 'touchstart', onDocumentTouchStart, false );
				document.addEventListener( 'touchmove', onDocumentTouchMove, false );

				//

				window.addEventListener( 'resize', onWindowResize, false );

			}

			function onWindowResize() {

				windowHalfX = window.innerWidth / 2;
				windowHalfY = window.innerHeight / 2;

				camera.aspect = window.innerWidth / window.innerHeight;
				camera.updateProjectionMatrix();

				renderer.setSize( window.innerWidth, window.innerHeight );

			}

			//

			function onDocumentMouseMove(event) {

				mouseX = event.clientX - windowHalfX;
				mouseY = event.clientY - windowHalfY;

			}

			function onDocumentTouchStart( event ) {

				if ( event.touches.length > 1 ) {

					event.preventDefault();

					mouseX = event.touches[ 0 ].pageX - windowHalfX;
					mouseY = event.touches[ 0 ].pageY - windowHalfY;

				}

			}

			function onDocumentTouchMove( event ) {

				if ( event.touches.length == 1 ) {

					event.preventDefault();

					mouseX = event.touches[ 0 ].pageX - windowHalfX;
					mouseY = event.touches[ 0 ].pageY - windowHalfY;

				}

			}

			//

			function animate() {

				requestAnimationFrame( animate );

				render();

			}

			function render() {

				camera.position.x += ( mouseX - camera.position.x ) * .05;
				camera.position.y += ( - mouseY + 200 - camera.position.y ) * .05;
				camera.lookAt( scene.position );

				renderer.render( scene, camera );

			}
<script src="http://threejs.org/build/three.min.js"></script>
<script src="http://threejs.org/examples/js/renderers/Projector.js"></script>
<script src="http://threejs.org/examples/js/renderers/CanvasRenderer.js"></script>

所以我决定使用该演示在可点击元素中制作每个球形顶点。在链接中。

我一周以来一直在尝试这个,但我找不到解决办法,我最好的办法就是:

			var container;
			var camera, scene, renderer;

			var raycaster;
			var mouse;

			var PI2 = Math.PI * 2;

			var programStroke = function ( context ) {

				context.beginPath();
				context.arc( 0, 0, 0.5, 0, PI2, true );
				context.fill();

			};

			var programFill = function ( context ) {

				context.lineWidth = 0.025;
				context.beginPath();
				context.arc( 0, 0, 0.5, 0, PI2, true );
				context.stroke();

			};

			var INTERSECTED;

			init();
			animate();

			function init() {

				container = document.createElement( 'div' );
				document.body.appendChild( container );

				camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 10000 );
				camera.position.set( 0, 300, 500 );

				scene = new THREE.Scene();

				for ( var i = 0; i < 200; i ++ ) {

					var particle = new THREE.Sprite( new THREE.SpriteCanvasMaterial( { color: Math.random() * 0x000fff , program: programStroke } ) );
					particle.position.x = Math.random() * 800 - 400;
					particle.position.y = Math.random() * 800 - 400;
					particle.position.z = Math.random() * 800 - 400;
					particle.scale.x = particle.scale.y = Math.random() * 10 + 10;
					particle.data = { url: "http://google.com" }
					scene.add( particle );

				}
				
				
				raycaster = new THREE.Raycaster();
				mouse = new THREE.Vector2();

				renderer = new THREE.CanvasRenderer();
				renderer.setClearColor( 0xffffff );
				renderer.setPixelRatio( window.devicePixelRatio );
				renderer.setSize( window.innerWidth, window.innerHeight );
				container.appendChild( renderer.domElement );

				document.addEventListener( 'mousemove', onDocumentMouseMove, false );
				 document.addEventListener('mousedown', onDocumentMouseDown, false);

				//

				window.addEventListener( 'resize', onWindowResize, false );

			}

			function onWindowResize() {

				camera.aspect = window.innerWidth / window.innerHeight;
				camera.updateProjectionMatrix();

				renderer.setSize( window.innerWidth, window.innerHeight );

			}

			function onDocumentMouseMove( event ) {

				event.preventDefault();

				mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
				mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;

			}

			//

			function animate() {

				requestAnimationFrame( animate );

				render();

			}

			function onDocumentMouseDown(event) {
    
    
				raycaster.setFromCamera( mouse, camera );

				var intersects = raycaster.intersectObjects( scene.children );

				if ( intersects.length > 0 ) {

					window.open("http://www.w3schools.com");

					INTERSECTED = null;

				}
				
			}

			var radius = 600;
			var theta = 0;

			function render() {

				// rotate camera

				theta += 0.1;

				camera.position.x = radius * Math.sin( THREE.Math.degToRad( theta ) );
				camera.position.y = radius * Math.sin( THREE.Math.degToRad( theta ) );
				camera.position.z = radius * Math.cos( THREE.Math.degToRad( theta ) );
				camera.lookAt( scene.position );

				camera.updateMatrixWorld();

				// find intersections

				raycaster.setFromCamera( mouse, camera );



				renderer.render( scene, camera );

			}
<script src="http://threejs.org/build/three.min.js"></script>
<script src="http://threejs.org/examples/js/renderers/Projector.js"></script>
<script src="http://threejs.org/examples/js/renderers/CanvasRenderer.js"></script>

这不是我想要的,但至少它是一个可点击的粒子。但是,当我点击粒子时,如何随机使用多个链接?

我在three.js库中发现了这个例子http://threejs.org/examples/#canvas_interactive_particles有一个交互,但没有我想要它。我试图将元素修改为可点击但我找不到解决方案。

你有什么建议吗?

谢谢

1 个答案:

答案 0 :(得分:0)

请参阅此回答 - three.js click single particle

关键是将所有粒子附加到粒子阵列,以便稍后进行光照。

附加的小提琴有一个如何改变粒子相互作用的材料的例子。