three.js通过three.path库绘制带符号和动画的路径

622 阅读1分钟

项目中用到的,记录一下,防止下次要用又找不到了。。。

  • vue3
  • three.js
  • three.path
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { PathGeometry, PathPointList } from "three.path";
let scene, camera, renderer;
init();
cline();
animate();

function init() {
  scene = new THREE.Scene();
  camera = new THREE.PerspectiveCamera(
    40,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  );
  camera.position.z = 200;

  renderer = new THREE.WebGLRenderer({
    alpha: true,
    antialias: true,
  });
  renderer.setSize(window.innerWidth, window.innerHeight);

  renderer.render(scene, camera);
  document.body.appendChild(renderer.domElement);

  const controls = new OrbitControls(camera, renderer.domElement);
  controls.addEventListener("change", () => {
    renderer.render(scene, camera);
  });
}

function cline() {
  let curve = [
    5, 0, 0, 0, 0, 0, 10, 10, 0, 0, 20, 0, -10, -10, 0, 15, 0, 0, 25, -10, 0,
    40, -10, 0, 40, -20, 0,
  ];

  // 定义空数组,存储三维坐标
  let points = [];
  for (let i = 0; i < curve.length; i += 3) {
    points.push(new THREE.Vector3(curve[i], curve[i + 1], curve[i + 2]));
  }

  // 生成曲线
  let pathCurve = new THREE.CatmullRomCurve3(points, false, "catmullrom", 0);

  // 贴图加载
  const arrow = new THREE.TextureLoader().load("/arrow.png");

  // 贴图重复设置
  arrow.wrapS = arrow.wrapT = THREE.RepeatWrapping;
  arrow.repeat.x = 1;
  arrow.repeat.y = 1;
  
  // 向异性(追求贴图真实感可以设置,我这里材质都选的基础材质,就没那么讲究了)
  // arrow.anisotropy = renderer.capabilities.getMaxAnisotropy();

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

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

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

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

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

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

  // 创建路径的网格模型
  let path = new THREE.Mesh(geometry, material);

  // 添加到场景
  scene.add(path);


  // 在每一帧渲染的时候,更新贴图沿x轴的偏移量,形成uv动画效果
  function textureLoop() {
    if (arrow) {
      arrow.offset.x -= 0.02;
    }
    requestAnimationFrame(textureLoop);
  }
  textureLoop();
}

function animate() {
  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}