ui 在設計圖中給了一張小球, 要求球作成旋轉的效果html
我一看這個不是有點 3 d 的效果嗎. 而且這球之間的關係一點都很差構建啊. 因而我在腦內構建了很是炫酷的效果. 可是苦於沒有思路前端
後來在羣裏問羣友, 羣友給了一個思路, 因而我在網上找到了一篇關於騰訊前端設計高的粒子特效. 文章放在這裏 (https://tgideas.qq.com/webplat/info/news_version3/804/7104/7106/m5723/201704/577405.shtml)web
從這篇文章來看, 是先設計出 3d 模型, 而後把 3d 模型利用 three.js 的 loader 加載進來解析. 其中主要的就是模型頂點的數據canvas
因而恰巧有個同事會 3d 建模, 因而拜託他建了一個 3d模型, dom
雖然和原圖相差太大, 可是馬馬虎虎還能夠用. 可是這個模型還有點解析不正常, 後來讓我讓他改了不少遍, 簡直想死啊, 模型到手後就開始作解析ide
loader.load('./model/xiaoqiu2.obj', function (geo) { geo.traverse(function (child) { if (child.isMesh) { THREE.GeometryUtils.merge(ball, new THREE.Geometry().fromBufferGeometry(child.geometry)); } }) ball.normalize() ball.scale(100, 100, 100); var starField = new THREE.Points(ball, starsMaterial); scene.add(starField); })
這裏. obj 格式的模型直接加載進來是 一個group. 這個 group 裏面有許多的 mesh, 這樣全部的頂點數據就很差找, 若是想作粒子切換效果, 須要把 mesh 合併爲一個. 這裏我使用GeometryUtils來作合併. 合併以後的能夠直接在vertices裏面拿到模型全部的頂點數據. 而後作一個旋轉動畫動畫
var animate = function () { ball.rotateX(0.01) ball.rotateY(0.01) ball.rotateZ(0.01) renderer.render(scene, camera); globalID = requestAnimationFrame(animate); };
效果以下ui
其實我本來也想加個球到文字的切換效果, 可是後來發現太卡, 因而去掉了. 這裏把參考代碼放上idea
切換使用的是 Tween.js spa
for (var i = 0; i < sourceLength; i++) { var o = target.vertices[i % length]; new TWEEN.Tween(source.vertices[i]).to({ x: o.x, y: o.y, z: o.z }, 0).easing(TWEEN.Easing.Exponential.In).delay(5000 * Math.random()).start() }
關於文字是先用 canvas 畫出想要的文字, 而後把頂點數據導出來
function getTextData(text) { // 建立canvas const textCanvas = document.createElement('canvas'); const textCtx = textCanvas.getContext('2d'); function map(n, a, b, c, d) { return (n - a) * (d - c) / (b - a) + c; } function generatePointsFromImgData(imgData) { let points = []; let {data, width: w, height: h} = imgData; let multX = 1; let multY = 1; let aspect = w / h; if (aspect > 1) { multX = aspect; } else if (aspect < 1) { multY = h / w; } let offsetX = multX * 0.5; let offsetY = multY * 0.5; for (let i = 3; i < data.length; i += 4) { if (data[i] <= 0x20) { continue; } let j = i * 0.25; let x = j % w; let y = Math.floor(j / w); let tX = x / w; let tY = y / h; let vX = tX * multX - offsetX; let vY = tY * multY - offsetY; // let vZ = (Math.random() * 2 - 1) * 0.1 - 0.05; let vZ = Math.sin((Math.sin(tX * 4) * 3 + Math.cos(tY * 2) * 2) * 8) * 0.2; let p = new THREE.Vector3(vX, -vY, vZ).multiplyScalar(0.7); points.push(p); } return points; } function generatePointsFromWord(text = 'Jquery') { textCtx.resetTransform(); textCtx.clearRect(0, 0, textCanvas.width, textCanvas.height); textCtx.fillStyle = 'white'; let h = map(text.length, 1, 25, 48, 12); textCtx.font = `normal ${h}px Arial`; textCtx.textBaseline = 'middle'; textCtx.textAlign = 'center'; let w = Math.floor(textCtx.measureText(text).width); textCtx.fillText(text, w * 0.5, h * 0.5); let imgData = textCtx.getImageData(0, 0, w, h); textCtx.clearRect(0, 0, textCanvas.width, textCanvas.height); return generatePointsFromImgData(imgData); } return generatePointsFromWord(text); }
這樣就能夠在兩個模型之間作切換了