一、背景
創(chuàng)新互聯(lián)堅持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都網(wǎng)站設(shè)計、成都做網(wǎng)站、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時代的茌平網(wǎng)站設(shè)計、移動媒體設(shè)計的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!
粒子特效是為模擬現(xiàn)實中的水、火、霧、氣等效果由各種三維軟件開發(fā)的制作模塊,原理是將無數(shù)的單個粒子組合使其呈現(xiàn)出固定形態(tài),借由控制器、腳本來控制其整體或單個的運(yùn)動,模擬出現(xiàn)真實的效果。three.js是用JavaScript編寫的WebGL的第三方庫,three.js提供了豐富的API幫助我們?nèi)崿F(xiàn)3D動效,本文主要介紹如何使用three.js實現(xiàn)粒子過渡效果,以及基本的鼠標(biāo)交互操作。
(注:本文使用的關(guān)于three.js的API都是基于版本r98的。)
二、實現(xiàn)步驟
1. 創(chuàng)建渲染場景scene
scene實際上相當(dāng)于一個三維空間,用于承載和顯示我們所定義的一切,包括相機(jī)、物體、燈光等。在實際開發(fā)時為了方便觀察可添加一些輔助工具,比如網(wǎng)格、坐標(biāo)軸等。
scene = new THREE.Scene(); scene.fog = new THREE.Fog(0x05050c, 10, 60); scene.add( new THREE.GridHelper( 2000, 1 ) ); // 添加網(wǎng)格
2. 添加照相機(jī)camera
THREE里面實現(xiàn)了幾種相機(jī):PerspectiveCamera(透視相機(jī))、 OrthographicCamera(正交投影相機(jī))、CubeCamera(立方體相機(jī)或全景相機(jī))和 StereoCamera(3D相機(jī))。本文介紹我們主要用到的 PerspectiveCamera(透視相機(jī)):
視覺效果是近大遠(yuǎn)小。
配置參數(shù) PerspectiveCamera(fov, aspect, near, far)。
fov:相機(jī)的可視角度。
aspect:相機(jī)可視范圍的長寬比。
near:相對于深度剪切面的遠(yuǎn)的距離。
far:相對于深度剪切面的遠(yuǎn)的距離。
camera = new THREE.PerspectiveCamera(45, window.innerWidth /window.innerHeight, 5, 100); camera.position.set(10, -10, -40); scene.add(camera);
3. 添加場景渲染需要的燈光
three.js里面實現(xiàn)的光源:AmbientLight(環(huán)境光)、DirectionalLight(平行光)、HemisphereLight(半球光)、PointLight(點光源)、RectAreaLight(平面光源)、SpotLight(聚光燈)等。配置光源參數(shù)時需要注意顏色的疊加效果,如環(huán)境光的顏色會直接作用于物體的當(dāng)前顏色。各種光源的配置參數(shù)有些區(qū)別,下面是本文案例中會用到的二種光源。
let ambientLight = new THREE.AmbientLight(0x000000, 0.4); scene.add(ambientLight); let pointLight = new THREE.PointLight(0xe42107); pointLight.castShadow = true; pointLight.position.set(-10, -5, -10); pointLight.distance = 20; scene.add(pointLight);
4. 創(chuàng)建、導(dǎo)出并加載模型文件loader
創(chuàng)建模型,可以使用three.js editor進(jìn)行創(chuàng)建或者用three.js的基礎(chǔ)模型生成類進(jìn)行生成,相對復(fù)雜的或者比較特殊的模型需要使用建模工具進(jìn)行創(chuàng)建(c4d、3dmax等)。
使用three.js editor進(jìn)行創(chuàng)建,可添加基本幾何體,調(diào)整幾何體的各種參數(shù)(位置、顏色、材質(zhì)等)。
使用模型類生成。
let geometryCube = new THREE.BoxBufferGeometry( 1, 1, 1 ); let materialCube = new THREE.MeshBasicMaterial( {color: 0x00ff00} ); let cubeMesh = new THREE.Mesh( geometryCube, materialCube ); scene.add( cubeMesh );
導(dǎo)出需要的模型文件(此處使用的是 obj格式的模型文件)。
加載并解析模型文件數(shù)據(jù)。
let onProgress = function (xhr) { if (xhr.lengthComputable) { // 可進(jìn)行計算得知模型加載進(jìn)度 } }; let onError = function () {}; particleSystem = new THREE.Group(); var texture = new THREE.TextureLoader().load('./point.png'); new THREE.OBJLoader().load('./model.obj', function (object) { // object 模型文件數(shù)據(jù) }, onProgress, onError);
5. 將導(dǎo)入到模型文件轉(zhuǎn)換成粒子系統(tǒng)Points
獲取模型的坐標(biāo)值。
拷貝粒子坐標(biāo)值到新建屬性position1上 ,這個作為粒子過渡效果的最終坐標(biāo)位置。
給粒子系統(tǒng)添加隨機(jī)三維坐標(biāo)值position,目的是把每個粒子位置打亂,設(shè)定起始位置。
let color = new THREE.Color('#ffffff'); let material = new THREE.PointsMaterial({ size: 0.2, map: texture, depthTest: false, transparent: true }); particleSystem= new THREE.Group(); let allCount = 0 for (let i = 0; i < object.children.length; i++) { let name = object.children[i].name let _attributes = object.children[i].geometry.attributes let count = _attributes.position.count _attributes.positionEnd = _attributes.position.clone() _attributes.position1 = _attributes.position.clone() for (let i = 0; i < count * 3; i++) { _attributes.position1.array[i]= Math.random() * 100 - 50 } let particles = new THREE.Points(object.children[i].geometry, material) particleSystem.add(particles) allCount += count } particleSystem.applyMatrix(new THREE.Matrix4().makeTranslation(-5, -5,-10));
6. 通過tween動畫庫實現(xiàn)粒子坐標(biāo)從position到position1點轉(zhuǎn)換
利用 TWEEN 的緩動算法計算出各個粒子每一次變化的坐標(biāo)位置,從初始位置到結(jié)束位置時間設(shè)置為2s(可自定義),每次執(zhí)行計算之后都需要將attributes的position屬性設(shè)置為true,用來提醒場景需要更新,在下次渲染時,render會使用最新計算的值進(jìn)行渲染。
let pos = { val: 1 }; tween = new TWEEN.Tween(pos).to({ val: 0 }, 2500).easing(TWEEN.Easing.Quadratic.InOut).onUpdate(callback); tween.onComplete(function () { console.log('過渡完成complete') }) tween.start(); function callback() { let val = this.val; let particles = particleSystem.children; for (let i = 0; i < particles.length; i++) { let _attributes = particles[i].geometry.attributes let name = particles[i].name if (name.indexOf('_') === -1) { let positionEnd =_attributes.positionEnd.array let position1 =_attributes.position1.array let count =_attributes.position.count for (let j = 0; j < count *3; j++) { _attributes.position.array[j] = position1[j] *val + positionEnd[j] * (1 - val) } } _attributes.position.needsUpdate = true // 設(shè)置更新 } }
7. 添加渲染場景render
創(chuàng)建容器。
定義render渲染器,設(shè)置各個參數(shù)。
將渲染器添加到容器里。
自定義的渲染函數(shù) render,在渲染函數(shù)里面我們利用 TWEEN.update 去更新模型的狀態(tài)。
調(diào)用自定義的循環(huán)動畫執(zhí)行函數(shù) animate,利用requestAnimationFrame方法進(jìn)行逐幀渲染。
let container = document.createElement('div'); document.body.appendChild(container); renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); renderer.setPixelRatio(window.devicePixelRatio); renderer.setClearColor(scene.fog.color); renderer.setClearAlpha(0.8); renderer.setSize(window.innerWidth, window.innerHeight); container.appendChild(renderer.domElement); // 添加webgl渲染器 function render() { particleSystem.rotation.y += 0.0001; TWEEN.update(); particleSystem.rotation.y += (mouseX + camera.rotation.x) * .00001; camera.lookAt(new THREE.Vector3(-10, -5, -10)) controls.update(); renderer.render(scene, camera); } function animate() { // 開始循環(huán)執(zhí)行渲染動畫 requestAnimationFrame(animate); render(); }
8. 添加鼠標(biāo)操作事件實現(xiàn)角度控制
我們還可以添加鼠標(biāo)操作事件實現(xiàn)角度控制,其中winX、winY分別為window的寬高的一半,當(dāng)然具體的坐標(biāo)位置可以根據(jù)自己的需求進(jìn)行計算,具體的效果如下圖所示。
document.addEventListener('mousemove', onDocumentMouseMove, false); function onDocumentMouseMove(event) { mouseX = (event.clientX - winX) / 2; mouseY = (event.clientY - winY) / 2; }
三、優(yōu)化方案
1. 減少粒子數(shù)量
隨著粒子數(shù)量的增加,需要的計算每個粒子的位置和大小將會非常耗時,可能會造成動畫卡頓或出現(xiàn)頁面假死的情況,所以我們在建立模型時可盡量減少粒子的數(shù)量,能夠有效提升性能。
在以上示例中,我們改變導(dǎo)出模型的精細(xì)程度,可以得到不同數(shù)量的粒子系統(tǒng),當(dāng)粒子數(shù)量達(dá)到幾十萬甚至幾百萬的時候,在動畫加載時可以感受到明顯的卡頓現(xiàn)象,這主要是由于fps比較低,具體的對比效果如下圖所示,左邊粒子數(shù)量為30萬,右邊粒子數(shù)量為6萬,可以明顯看出左邊跳幀明顯,右邊基本保持比較流暢的狀態(tài)。
2. 采用GPU渲染方式
編寫片元著色器代碼,利用webgl可以為canvas提供硬件3D加速,瀏覽器可以更流暢地渲染頁面。目前大多數(shù)設(shè)備都已經(jīng)支持該方式,需要注意的是在低端的設(shè)備上由于硬件設(shè)備原因,渲染的速度可能不及基于cpu計算的方式渲染。
四、總結(jié)
綜上所述,實現(xiàn)粒子動效的關(guān)鍵在于計算、維護(hù)每個粒子的位置狀態(tài),而three.js提供了較為便利的方法,可以用于渲染整個粒子場景。當(dāng)粒子數(shù)量極為龐大時,想要實現(xiàn)較為流暢的動畫效果需要注意優(yōu)化代碼、減少計算等,也可以通過提升硬件配置來達(dá)到效果。本文中的案例為大家展示了3D粒子動效如何實現(xiàn),大家可以根據(jù)自己的實際需求去制作更炫酷的動態(tài)效果。
好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,謝謝大家對創(chuàng)新互聯(lián)的支持。
新聞名稱:基于three.js實現(xiàn)的3D粒子動效實例代碼
分享網(wǎng)址:http://jinyejixie.com/article18/jjipdp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計、外貿(mào)建站、面包屑導(dǎo)航、關(guān)鍵詞優(yōu)化、網(wǎng)站內(nèi)鏈、定制網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)