使用 three.js 來做球的 3d 特效


ui 在設計圖中給了一張小球, 要求球做成旋轉的效果

我一看這個不是有點 3 d 的效果嗎. 並且這球之間的關系一點都不好構建啊. 於是我在腦內構建了非常炫酷的效果. 但是苦於沒有思路

后來在群里問群友, 群友給了一個思路, 於是我在網上找到了一篇關於騰訊前端設計高的粒子特效. 文章放在這里 (https://tgideas.qq.com/webplat/info/news_version3/804/7104/7106/m5723/201704/577405.shtml)

從這篇文章來看, 是先設計出 3d 模型, 然后把 3d 模型利用 three.js 的 loader 加載進來解析. 其中主要的就是模型頂點的數據

於是恰巧有個同事會 3d 建模, 於是拜托他建了一個 3d模型, 

雖然和原圖相差太大, 但是馬馬虎虎還可以用. 但是這個模型還有點解析不正常, 后來讓我讓他改了很多遍,  簡直想死啊,  模型到手后就開始做解析

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);
    };

效果如下

其實我原本也想加個球到文字的切換效果, 但是后來發現太卡, 於是去掉了. 這里把參考代碼放上

切換使用的是 Tween.js  

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);

    }

這樣就可以在兩個模型之間做切換了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM