今天我們來用ThreeJS的庫實現一個波紋粒子效果,我們用到的ThreeJS的庫有CanvasRenderer.js,OrbitControls.js,Projector.js,stats.min.js和three.js。這些庫都是不可或缺的,我們先來看看實現的效果,如下圖所示。
我們再來看看項目結構是怎么樣的,項目結構如下圖所示。
我們的效果全部寫在了index.html里,現在我們直接貼出index.html的代碼,同學們可以直接拿來運行,代碼如下。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>演示頁面</title> <script src="three.js"></script> <script src="Projector.js"></script> <script src="CanvasRenderer.js"></script> <script src="stats.min.js"></script> <script src="OrbitControls.js"></script> </head> <body> </body> <script> var SEPARATION = 200, AMOUNTX = 60, AMOUNTY = 60; var container, stats; var camera, scene, renderer, controls; var particles, particle, count = 0; var windowHalfX = window.innerWidth / 2; var windowHalfY = window.innerHeight / 2; var raycaster = new THREE.Raycaster(); var mouse = new THREE.Vector2(); function init() { container = document.createElement('div'); document.body.appendChild(container); camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000); scene = new THREE.Scene(); /** * 設置光源 * */ //點光源 var point = new THREE.PointLight(0xffffff);//白光 point.position.set(1200, 1200, 1200);//點光源位置 scene.add(point);//點光源添加進場景 //環境光 var ambient = new THREE.AmbientLight(0x999999);//白光 scene.add(ambient);//環境光添加進場景 //模型 var cubeGeometry = new THREE.CubeGeometry(1000, 1000, 1000); var cubeMaterial = new THREE.MeshLambertMaterial({ color:0xffff00 //side:THREE.DoubleSide });//材質對象 var cubeMesh = new THREE.Mesh(cubeGeometry, cubeMaterial);//網格模型對象 cubeMesh.translateY(500); scene.add(cubeMesh);//正方體網格模型添加到場景中 //粒子 particles = new Array(); 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 i = 0; for (var ix = 0; ix < AMOUNTX; ix++) { for (var iy = 0; iy < AMOUNTY; iy++) { particle = particles[i++] = new THREE.Sprite(material); particle.position.x = ix * SEPARATION - ((AMOUNTX * SEPARATION) / 2); particle.position.z = iy * SEPARATION - ((AMOUNTY * SEPARATION) / 2); scene.add(particle); } } /** * 創建渲染器對象 * */ renderer = new THREE.CanvasRenderer(); renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(window.innerWidth, window.innerHeight); container.appendChild(renderer.domElement); window.addEventListener('resize', onWindowResize, false); //交互控制器 /** * 鼠標鍵盤事件監聽器 * */ controls = new THREE.OrbitControls(camera, renderer.domElement); controls.enableDamping = true; controls.dampingFactor = 0.1; controls.screenSpacePanning = true; controls.minDistance = 0; controls.maxDistance = 5000; controls.maxPolarAngle = 2*Math.PI; /** * 模型拾取 * */ mouse.x = -10000; mouse.y = -10000; function onMouseMove( event ) { // calculate mouse position in normalized device coordinates // (-1 to +1) for both components mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1; mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1; } window.addEventListener( 'mousemove', onMouseMove, false ); } function pickUp() { // update the picking ray with the camera and mouse position raycaster.setFromCamera( mouse, camera ); // calculate objects intersecting the picking ray var intersects = raycaster.intersectObjects( scene.children ); for ( var i = 0; i < intersects.length; i++ ) { intersects[ i ].object.material.color.set( 0xff00ff ); } if(intersects.length === 0){ scene.children[2].material.color.set( 0xffff00 ); for(var i=3; i<scene.children.length; i++){ scene.children[i].material.color.set( 0xffffff ); } } renderer.render( scene, camera ); } function onWindowResize() { windowHalfX = window.innerWidth / 2; windowHalfY = window.innerHeight / 2; camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); } var rad = 0; function render() { camera.position.set(2600, 500, 2600); camera.up = new THREE.Vector3(0, 1, 0); camera.lookAt(new THREE.Vector3(0, 500, 0)); var i = 0; for (var ix = 0; ix < AMOUNTX; ix++) { for (var iy = 0; iy < AMOUNTY; iy++) { particle = particles[i++]; particle.position.y = (Math.sin((ix + count) * 0.2) * 500) + (Math.sin((iy + count) * 0.2) * 500); particle.scale.y = (Math.sin((ix + count) * 0.3) + 1) * 3 + (Math.sin((iy + count) * 0.3) + 1) * 3; particle.scale.x = (Math.sin((ix + count) * 0.3) + 1) * 3 + (Math.sin((iy + count) * 0.3) + 1) * 3; } scene.children[2].translateY(Math.cos(ix + count/2)*5); } //模型旋轉 scene.children[2].rotateY(Math.PI/180); camera.position.x = 2600*Math.cos(Math.PI/180*rad); camera.position.z = -2600*Math.sin(Math.PI/180*rad); //點光源位置 scene.children[0].position.x = 1200*Math.cos(Math.PI/180*rad+Math.PI*0.1); scene.children[0].position.z = -1200*Math.sin(Math.PI/180*rad+Math.PI*0.1); controls.update(); renderer.render(scene, camera); count += 0.1; rad += 0.2; } function animate() { requestAnimationFrame(animate); render(); pickUp(); } init(); animate(); </script> </html>
我們分析一下段代碼,首先我們看到requestAnimationFrame,這是主循環,我們在init()初始化函數中往scene場景中添加了particle粒子,這些粒子是在XoZ平面上均勻網格散布的。然后我們主循環每次render()都改變粒子的Y坐標,修改的規則是通過sin函數進行Y軸向擾動。每次重繪我們都修改Y坐標,就實現了粒子的波動特效。
代碼很簡單,希望能幫助大家做出一套粒子波動的背景特效。鯽魚非常願意和大家討論學習WebGL和ThreeJS的技術,歡迎大家留言,謝謝。本文系原創,如需引用請注明出處:https://www.cnblogs.com/ccentry/p/10125686.html