zoukankan      html  css  js  c++  java
  • 使用 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,  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);
    
        }

    这样就可以在两个模型之间做切换了

  • 相关阅读:
    回调函数实例
    Java StringBuffer 和 StringBuilder 类
    excel被保护或者锁定时候按住alt和enter可以输入换行
    ArrayUtils.
    excel中在某一列上的所有单元格的前后增加
    decode(条件,值1,返回值1,值2,返回值2,...值n,返回值n,缺省值)
    正则表达式:Pattern类与Matcher类详解
    Cocos2d-x文本菜单
    msp430在ccsv5下出现的问题总结
    与TCP/IP协议的初次见面(一)
  • 原文地址:https://www.cnblogs.com/cgdx/p/10836883.html
Copyright © 2011-2022 走看看