Skip to content
章节导航

通过three.path生成流动的箭头实现光路效果

js
import { PathGeometry, PathPointList } from 'three.path';

export function createArrow(pointsArraysIn, tubeTextures, Object3D) {
  pointsArraysIn.forEach((item, i) => {
    // 多种img的方案
    // item.points.forEach((item) => res.push(new THREE.Vector3(...item)));
    // 单个img的方案
    item.points.forEach(async (child, j) => {
      const res = [];
      child.forEach((grandson) => res.push(new THREE.Vector3(...grandson)));
      const curve = new THREE.CatmullRomCurve3(res, false, 'catmullrom', 0);
      const texture = await new THREE.TextureLoader().loadAsync(item.img);
      tubeTextures.push(texture);
      // 贴图在水平方向上允许重复
      texture.wrapS = THREE.RepeatWrapping;

      // 向异性
      texture.anisotropy = window.renderer.capabilities.getMaxAnisotropy();

      // 创建一个合适的材质
      const material = new THREE.MeshPhongMaterial({
        map: texture,
        transparent: true,
        depthWrite: false,
        // blending: THREE.AdditiveBlending,
      });

      // 确定一个向上的向量
      const up = new THREE.Vector3(0, 1, 0);

      // 创建路径点的集合
      const pathPoints = new PathPointList();

      // 设置集合属性
      pathPoints.set(curve.getPoints(1000), 0.5, 2, up, false);

      // 创建路径几何体
      const geometry = new PathGeometry();

      // 更新几何体的属性
      geometry.update(pathPoints, {
        width: 50,
        arrow: false,
      });

      // 创建路径的网格模型并添加到Object3D中
      const mesh = new THREE.Mesh(geometry, material);
      mesh.name = `${i}_${j}`;
      Object3D.add(mesh);
    });
  });
}


let tubeTextures = []; // 所有的箭头流动的纹理
window.arrowObj = new THREE.Object3D(); // 所有的箭头
window.arrowObj.name = 'arrowObj';
window.scene.add(window.arrowObj);
// 生成路径的点位格式
const northPointsArraysIn = [
  // NorthCheckIn
  {
    points: [
      // 第一条线
      [
        [-277666.9158482149, 810.2652476201476, 421543.01641528937],
        [-277304.58284636436, 929.9716520377681, 421228.80283783353],
      ],
      [
        [-276880.84363197954, 987.9131771329446, 420859.18093394255],
        [-276502.57288221497, 1019.129922988365, 420518.06904489483],
      ],
      [
        [-276204.48275861307, 987.9131771329446, 420658.4899475818],
        [-275865.35997052357, 987.9131771329446, 421065.31374235614],
      ],
      [
        [-273254.01460832334, 1199.5825156727828, 424037.49320102535],
        [-272625.6624594882, 1199.5825156727828, 424753.8121480441],
      ],
      [
        [-269918.3714368394, 1166.9305476534462, 427865.9879619352],
        [-269062.07523671986, 1166.9305476534462, 428835.35548883147],
      ],
    ]
  }
]
// 生成所有箭头流动效果
createArrow(northPointsArraysIn, tubeTextures, window.arrowObj);

// 创建一个时钟对象Clock
const clock = new THREE.Clock();
// 设置渲染频率为60FBS,也就是每秒调用渲染器render方法大约60次
const FPS = 60;
const renderT = 1 / FPS; // 单位秒  间隔多长时间渲染渲染一次
// 声明一个变量表示render()函数被多次调用累积时间
// 如果执行一次renderer.render,timeS重新置0
let timeS = 0;
let T; // 两帧的时间间隔
function animateNorth() {
  window.loopId = requestAnimationFrame(animateNorth); // 请求动画帧
  window.orbit.update();
  // .getDelta()方法获得两帧的时间间隔
  T = clock.getDelta();
  timeS = timeS + T;
  // requestAnimationFrame默认调用render函数60次,通过时间判断,降低renderer.render执行频率
  if (timeS > renderT) {
    render();
    TWEEN.update();
    // 模型加载完成后执行此段代码
    if (modelLoaded) {
      // 箭头流动效果
      if (tubeTextures.length) {
        tubeTextures.forEach((texture) => {
          texture.offset.x -= 0.08;
        });
      }
   
    // renderer.render每执行一次,timeS置0
    timeS = 0;
  }
}