找回密码
 立即注册
首页 业界区 业界 ThreeJS 的效果样例流水管线(五)

ThreeJS 的效果样例流水管线(五)

固拆棚 2025-6-6 16:45:42
一、流水管线
1.gif

实现逻辑:
  1)先自定义几个点,通过CatmullRomCurve3生成一条平滑曲线
  2)根据生成的曲线在XY面扩展一个面,其中需要注意顶点索引、UV坐标添加的顺序,否则可能会导致绘制的图片混乱,不是完整的图片
  3)添加纹理同时设置偏移量实现流动效果
  4)为了保证显示的箭头图标不失真,根据管线的长度和图标的长度动态计算repeat的个数
2.gif
3.gif
  1. function addFlowByGeometry() {
  2.   // 自定义点
  3.   const points = [
  4.     new THREE.Vector3(-5, 5, 0),
  5.     new THREE.Vector3(-5, 0, 0),
  6.     new THREE.Vector3(0, 0, 0),
  7.     new THREE.Vector3(5, 0, 0),
  8.     new THREE.Vector3(5, -5, 3),
  9.   ];
  10.   // 生成一条平滑的曲线
  11.   const curve = new THREE.CatmullRomCurve3(points);
  12.   const srcGeometry = new THREE.TubeGeometry(curve, 64, 0.8, 32, false);
  13.   const srcMaterial = new THREE.MeshBasicMaterial({
  14.     color: 0x00ffff,
  15.     transparent: true,
  16.     opacity: 0.1,
  17.     side: THREE.DoubleSide // 两面都显示
  18.   });
  19.   const srcMesh = new THREE.Mesh(srcGeometry, srcMaterial);
  20.   scene.add(srcMesh);
  21.   // 定义曲面的分辨率
  22.   const widthSegments = 32;
  23.   const heightSegments = 32;
  24.   // 定义顶点位置和纹理坐标
  25.   const vertices = [];
  26.   const uvs = [];
  27.   // 定义扩展宽度
  28.   const width = 0.5;
  29.   for (let y = 0; y <= heightSegments; y++) {
  30.     for (let x = 0; x <= widthSegments; x++) {
  31.         const u = x / widthSegments;
  32.         const v = y / heightSegments;
  33.         // 获取曲线上的点
  34.         const point = curve.getPoint(u);
  35.         // 获取曲线的切线向量
  36.         const tangent = curve.getTangent(u);
  37.         // 计算法线向量
  38.         const normal = new THREE.Vector3(-tangent.y, tangent.x, 0).normalize();
  39.         // 扩展成平面
  40.         const px = point.x + normal.x * (v * 2 - 1) * width;
  41.         const py = point.y + normal.y * (v * 2 - 1) * width;
  42.         const pz = point.z;
  43.         vertices.push(px, py, pz);
  44.         uvs.push(u, v);
  45.     }
  46.   }
  47.   // 定义顶点索引
  48.   const indices = [];
  49.   for (let y = 0; y < heightSegments; y++) {
  50.     for (let x = 0; x < widthSegments; x++) {
  51.         const a = x + y * (widthSegments + 1);
  52.         const b = x + 1 + y * (widthSegments + 1);
  53.         const c = x + 1 + (y + 1) * (widthSegments + 1);
  54.         const d = x + (y + 1) * (widthSegments + 1);
  55.         indices.push(a, b, d);
  56.         indices.push(b, c, d);
  57.     }
  58.   }
  59.   // 创建一个自定义的 BufferGeometry
  60.   const geometry = new THREE.BufferGeometry();
  61.   // 将顶点位置添加到几何体
  62.   geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(vertices), 3));
  63.   // 将顶点索引添加到几何体
  64.   geometry.setIndex(new THREE.BufferAttribute(new Uint16Array(indices), 1));
  65.   // 将纹理坐标添加到几何体
  66.   geometry.setAttribute('uv', new THREE.BufferAttribute(new Float32Array(uvs), 2));
  67.   // 创建纹理加载器
  68.   const textureLoader = new THREE.TextureLoader();
  69.   // 加载纹理
  70.   const texture = textureLoader.load('Objects/imgs/arrow.png', () => {
  71.     texture.wrapS = THREE.RepeatWrapping;
  72.     texture.wrapT = THREE.RepeatWrapping;
  73.    
  74.     const originalWidth = texture.image.width;
  75.     const originalHeight = texture.image.height;
  76.     // 创建平面几何体
  77.     const [allWidth, allHeight] = [curve.getLength(), 1];
  78.     // 更新几何体的尺寸
  79.     texture.repeat.set(allWidth / (originalWidth * allHeight / 2 / originalHeight), 1);
  80.     // 创建材质
  81.     const material = new THREE.MeshBasicMaterial({ map: texture, side: THREE.DoubleSide, color: 0x00ffff, wireframe: false });
  82.     // 创建网格
  83.     const mesh = new THREE.Mesh(geometry, material);
  84.     // 将网格添加到场景中
  85.     scene.add(mesh);
  86.   });
  87.   setInterval(() => {
  88.     texture.offset.x -= 0.04;
  89.   }, 30)
  90. }
复制代码
流动管线
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

3 天前

举报

过来提前占个楼
您需要登录后才可以回帖 登录 | 立即注册