效果图

干货
<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>