Three.js 飞线效果

需求:

实现一个线条流动的效果,

实现方案:
1. 贴图+管道+贴图偏移 方案(这里暂不做介绍)

2. 向量+弧线+模型 方案

 

实现:

1.获取到需要实现效果的路径顶点信息

    
var geometrys = new THREE.Geometry()
var materialA = new THREE.MeshStandardMaterial({ color: 0x00ffff,side: THREE.DoubleSide });
    const geometry = new THREE.BoxGeometry();
    for ( let i = 0; i < number; i ++ ) {
      const mesh = new THREE.Mesh( geometry, materialA );
      mesh.position.x = Math.random() * 1600 - 800;
      mesh.position.y = 20;
      mesh.position.z = Math.random() * 1600 - 800;
      // mesh.scale.x = 20;
      mesh.scale.y = Math.random() * 80 + 10;
      // mesh.scale.z = 20;
      mesh.updateMatrix();
      mesh.matrixAutoUpdate = false;
      mesh.name = 'boxA';
      // mesh.shader = shader;
      // const axesHelper = new THREE.AxesHelper(100);
      // mesh.add(axesHelper);
      // console.log('顶点位置', mesh);
      geometrys.merge(mesh.geometry, mesh.matrix);
      this.pointslists.push(mesh.position)
      }


      const newMesh = new THREE.Mesh( geometrys, material );
      newMesh.name = 'boxB';
      // const a = new THREE.Euler(10, 0, 10, 'ZYX'); // 欧拉角
      // newMesh.rotation.setFromVector3(a);
      this.scene.add( newMesh );

 

2.创建路径线条+箭头模型

FlylineModel(){
      let that=this
      // 飞线模型
      this.flyGroup = new THREE.Group();
      var geometry = new THREE.BufferGeometry(); //创建一个缓冲类型几何体

      // 三维样条曲线
      console.log(this.pointslists.length);
      // this.pointslists.sort((a, b) => a.z - b.z)
      
      var curve = new THREE.CatmullRomCurve3(this.pointslists);
      curve.closed = true;
      console.log(`整个线段的已知点位中心位置:`,curve.getPoint(0.5),
      `弧长上的实际中心点位:`,curve.getPointAt(0.5)
      );
      //曲线上等间距返回多个顶点坐标
      that.points = curve.getPoints(100); //分段数100,返回101个顶点
      // that.points = curve.getPoints(curve.getLength()/100); //按整体长度的10/1的长度进行分段
      // 上面这俩的区别是一个是按已知点进行分段,一个是按曲线的实际长度进行分段

      // console.log(this.points)
      // setFromPoints方法从points中提取数据赋值给attributes.position
      geometry.setFromPoints(that.points);
      var material = new THREE.LineBasicMaterial({
        color: 0x5588aa, //轨迹颜色
      });
      //线条模型对象
      var line = new THREE.Line(geometry, material);
      line.scale.set(2, 0, 2);
      this.flyGroup.add(line);


      index = 1; //取点索引位置
      num = 15; //从曲线上获取点数量
      points2 = that.points.slice(index, index + num); //从曲线上获取一段
      // var curve = new THREE.CatmullRomCurve3(points2);
      // var newPoints2 = curve.getPoints(100); //获取更多的点数
      geometry2 = new THREE.BufferGeometry();
      geometry2.setFromPoints(that.points);
      // 每个顶点对应一个百分比数据attributes.percent 用于控制点的渲染大小
      var percentArr = []; //attributes.percent的数据
      for (var i = 0; i < that.points.length; i++) {
        percentArr.push(i / that.points.length);
      }
      var percentAttribue = new THREE.BufferAttribute(new Float32Array(percentArr), 1);
      geometry2.attributes.percent = percentAttribue;
      // 批量计算所有顶点颜色数据
      var colorArr = [];
      for (var i = 0; i < that.points.length; i++) {
        var color1 = new THREE.Color(0x5588aa); //轨迹线颜色 青色
        var color2 = new THREE.Color(0xef4136); //
        var color = color1.lerp(color2, i / that.points.length)
        colorArr.push(color.r, color.g, color.b);
      }
      // 设置几何体顶点颜色数据
      geometry2.attributes.color = new THREE.BufferAttribute(new Float32Array(colorArr), 3);

      // 点模型渲染几何体每个顶点
      var PointsMaterial = new THREE.PointsMaterial({
        // color: 0xffff00,
        size: 50.0, //点大小
        vertexColors: THREE.VertexColors, //使用顶点颜色渲染
      });
      var flyPoints = new THREE.Points(geometry2, PointsMaterial);
      flyPoints.scale.set(2, 0, 2);
      // 修改点材质的着色器源码(注意:不同版本细节可能会稍微会有区别,不过整体思路是一样的)
      PointsMaterial.onBeforeCompile = function (shader) {
        // 顶点着色器中声明一个attribute变量:百分比
        shader.vertexShader = shader.vertexShader.replace(
          'void main() {',
          [
            'attribute float percent;', //顶点大小百分比变量,控制点渲染大小
            'void main() {',
          ].join('\n') // .join()把数组元素合成字符串
        );
        // 调整点渲染大小计算方式
        shader.vertexShader = shader.vertexShader.replace(
          'gl_PointSize = size;',
          [
            'gl_PointSize = percent * size;',
          ].join('\n') // .join()把数组元素合成字符串
        );
      };
      this.flyGroup.add(flyPoints);

      this.scene.add(this.flyGroup);

      // 飞线动画
      indexMax = this.points.length - num; //飞线取点索引范围
          
    },

 

3.更新箭头位置

    update() {
      let that = this
      // 飞线动画
      if(that.points){
          if (index > indexMax) index = 0;
          index += 1
          points2 = that.points.slice(index, index + num); // 从曲线上获取一段
          // console.log(points2)
          var curve = new THREE.CatmullRomCurve3(points2);
          var newPoints2 = curve.getPoints(100); // 获取更多的点数
          geometry2.setFromPoints(newPoints2);

          // this.camera.position.copy(curve.getPoint(2))

        }
}

 

posted @ 2024-07-11 10:45  睡到自然醒ccc  阅读(13)  评论(0编辑  收藏  举报