Three.js 依次连接线的结点并实现流动效果

效果图

干货

<template>
    <div id="container"></div>
</template>

<script>
    import * as THREE from 'three'
    import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls'

    let animateFlag = false;
    let textureTest = new THREE.TextureLoader().load('./static/img.png'); // 流动材质 找一个酷炫点的图~
    
    export default {
        name: 'lineAnimateNext',
        data() {
            return {}
        },
        mounted() {
            var container = document.getElementById('container');
            var scene = new THREE.Scene();
            var camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, .1, 1000);
            camera.position.set(10, 10, 10);
            
            var gridHelper = new THREE.GridHelper(20);
            scene.add(gridHelper);
            
            var renderer = new THREE.WebGLRenderer({antialias: true, alpha: true});
            renderer.setSize(window.innerWidth, window.innerHeight);
            renderer.setPixelRatio(window.devicePixelRatio);
            container.appendChild(renderer.domElement);
            var controls = new OrbitControls(camera, renderer.domElement);
    
            // 光源
            scene.add(new THREE.AmbientLight(0xffffff));
            
            // 组装数据
            let a = [-10, 0, 10];
            let b = [-5, 5, 5];
            let c = [0, 0, 0];
            let d = [5, -5, 5];
            let e = [10, 0, 0];
            let f = [10, 5, 0];
            let g = [10, 0, 5];
            let arrs1 = [], arrs2 = [], arrs3 = [], arrs4 = [], arrs5 = [];
            
            arrs1.push(new THREE.Vector3(a[0], a[1], a[2]));
            arrs1.push(new THREE.Vector3(c[0], c[1], c[2]));

            arrs2.push(new THREE.Vector3(b[0], b[1], b[2]));
            arrs2.push(new THREE.Vector3(d[0], d[1], d[2]));

            arrs3.push(new THREE.Vector3(d[0], d[1], d[2]));
            arrs3.push(new THREE.Vector3(f[0], f[1], f[2]));

            arrs4.push(new THREE.Vector3(f[0], f[1], f[2]));
            arrs4.push(new THREE.Vector3(e[0], e[1], e[2]));
            arrs4.push(new THREE.Vector3(g[0], g[1], g[2]));

            arrs5.push(new THREE.Vector3(g[0], g[1], g[2]));
            arrs5.push(new THREE.Vector3(a[0], a[1], a[2]));
    
            // 渲染
            let playIndex = 1, playIndex2 = 0, finishedTimes = 0, animationFrameID;
            let playPoints = [[arrs1], [arrs2, arrs3], [arrs4], [arrs5]]; // 按照顺序动态连线
            
            createCurveShape(playPoints[0][0], playPoints[0].length);
            function createCurveShape(arrs, len) {
                let curve = new THREE.SplineCurve3(arrs);
                curve.autoClose = false;
                let points = curve.getPoints(10);
                let length = points.length;
                let val = 0;
                
                renderPoint();
                function renderPoint() {
                    animationFrameID = requestAnimationFrame(renderPoint);
                    
                    if(val == length - 1){
                        window.cancelAnimationFrame(animationFrameID);
                        // 间隔时间
                        if(playIndex < playPoints.length){
                            setTimeout(()=>{
                                animationFrameID = requestAnimationFrame(renderPoint);
                                drawLine();
                            }, 1000);
                        }
                        return;
                    }
        
                    drawLine();
                }
                
                
                function drawLine() {
                    if (val == length - 1) {
                        if(playIndex >= playPoints.length){ // 动画连线结束
                            finishedTimes++;
    
                            // 避免重复渲染的问题
                            if(finishedTimes == 1){
                                setTimeout(function(){
                                    /*
                                    * 数据量大的时候需要注意:
                                    * 1、使用贴图连接需要给 tubeMesh 添加 name,然后在这里进行删除操作
                                    * 2、重新添加一个不被截断的管道进行流动
                                    * 代码:略
                                    * */
            
                                    animateFlag = true;
                                }, 500);
                            }
                        }else{ // 连接下一根曲线
                            let playArr = playPoints[playIndex] || [];
                            playIndex2++;
                            for (let i = 0; i < playArr.length; i++) {
                                createCurveShape(playArr[i], playArr.length);
                            }
            
                            if(playIndex2 == len){
                                playIndex++;
                                playIndex2 = 0;
                            }
                        }
                        return;
                    }
    
                    let subPoints1 = points[val];
                    let subPoints2 = points[(val + 1) % length];
                    
                    let subPoints = [];
                    subPoints.push(subPoints1);
                    subPoints.push(subPoints2);
    
                    // 1、使用线连接
                    /*let geometryPoints = new THREE.BufferGeometry().setFromPoints(subPoints);
                    let line = new THREE.Line(geometryPoints, new THREE.LineBasicMaterial({color: 0xff0000}));
                    scene.add(line);*/
    
                    // 2、使用贴图连接
                    let curve = new THREE.CatmullRomCurve3(subPoints, false); /* 是否闭合 */
                    let tubeGeometry = new THREE.TubeGeometry(curve, 1, 0.2, 3, false); // path, tubularSegments, radius, radiusSegments, closed
                    textureTest.wrapS = THREE.RepeatWrapping;
                    textureTest.wrapT = THREE.RepeatWrapping;
                    let tubeMaterial = new THREE.MeshPhongMaterial({
                        map: textureTest,
                        transparent: true
                    });
                    let tubeMesh = new THREE.Mesh(tubeGeometry, tubeMaterial);
                    scene.add(tubeMesh);
                    
                    val++;
                }
            }
            
            render();
            function render() {
                if(animateFlag){
                    textureTest.offset.x += 0.06;
                }
                
                controls.update();
                requestAnimationFrame(render);
                renderer.render(scene, camera);
            }
        }
    }
</script>

<style lang="less">
    * {
        box-sizing: border-box;
        margin: 0;
        padding: 0;
    }
    
    body {
        overflow: hidden;
        font-family: Lato, sans-serif;
        width: 100%;
        height: 100%;
        background-color: #dedede;
        color: #202020;
        padding: 20px;
        text-shadow: 0 1px 0 rgba(255, 255, 255, .5);
    }
    
    #container {
        position: absolute;
        left: 0;
        top: 0;
        right: 0;
        bottom: 0;
        width: 100%;
        height: 100%;
        border: 1px solid #ff0000;
    }
</style>

猜你喜欢

发表评论

最新发布