使用MeshLine在Three.js中创建动态线条

845 阅读3分钟

MeshLine:基础

首先,创建一个新项目并安装Three.js。正如标题所述,我们不会使用LineBasicMaterial。我们将使用一个第三方模块,名为MeshLine。

在终端中安装它:npm install meshline

接下来,我们将把它导入到我们的项目中。

import { MeshLineGeometry, MeshLineMaterial } from 'meshline';

正如你所看到的,我们现在有了新的材质和几何体,用于线条。

像往常一样,将某物添加到场景中,我们需要创建一个几何体和一个材质,然后将它们组合成一个网格。

那么,让我们从几何体开始,创建一个MeshLineGeometry的新实例。

const geometry = new MeshLineGeometry();

接下来,我们创建一个数组。

const geometryPoints = [
  new THREE.Vector3(-2, 3, 0),
  new THREE.Vector3(3, 3, -2),
  new THREE.Vector3(0, -2, 0),
  new THREE.Vector3(-2, 0, 2),
  new THREE.Vector3(-2, 6, 5),
  new THREE.Vector3(5, 2, -3),
];

现在,我们将使用setPoints()方法将这些坐标分配给几何体。

geometry.setPoints(geometryPoints);

对于材质,我们将创建一个MeshLineMaterial类的新实例,并将颜色、宽度和分辨率作为属性传递。

const lineMaterial = new MeshLineMaterial({
  color: new THREE.Color(0xff0000),
  lineWidth: 1,
  resolution: new THREE.Vector2(window.innerWidth, window.innerHeight),
});

完成这些后,我们只需创建一个新的网格,将其添加到场景中,一切就绪!

const mesh = new THREE.Mesh(geometry, lineMaterial);
scene.add(mesh);

心形的动画

MeshLineMaterial带有一组属性。但在本文中,我将重点介绍其中的三个属性,这些属性将帮助我们实现最佳的动画效果。

首先,让我们创建一个循环,生成一个心形。

const geometry = new MeshLineGeometry();

// const geometryPoints = [
//   new THREE.Vector3(-2, 3, 0),
//   new THREE.Vector3(3, 3, -2),
//   new THREE.Vector3(0, -2, 0),
//   new THREE.Vector3(-2, 0, 2),
//   new THREE.Vector3(-2, 6, 5),
//   new THREE.Vector3(5, 2, -3),
// ];

const geometryPoints = [];
for (let t = 0; t <= Math.PI * 2; t += 0.01) {
  const x = 16 * Math.pow(Math.sin(t), 3);
  const y =
    13 * Math.cos(t) -
    5 * Math.cos(2 * t) -
    2 * Math.cos(3 * t) -
    Math.cos(4 * t);
  geometryPoints.push(new THREE.Vector3(x, y, 0));
}

geometry.setPoints(geometryPoints);

接下来,让我们更新相机的位置。

// camera.position.set(6, 8, 14);
camera.position.set(0, 0, 50);

我们需要的第一个属性是dashArray,顾名思义,它将连续的线条转换为虚线。

const lineMaterial = new MeshLineMaterial({
  color: new THREE.Color(0xff0000), // 线条颜色(此处为红色)
  lineWidth: 1,
  resolution: new THREE.Vector2(window.innerWidth, window.innerHeight),
  dashArray: 0.2,
});

为了让这个效果运动起来,我们将更新虚线偏移量。

为了让动画看起来像是用一条线绘制的,增加dashArray的值。

const lineMaterial = new MeshLineMaterial({
  color: new THREE.Color(0xff0000), // 线条颜色(此处为红色)
  lineWidth: 1,
  resolution: new THREE.Vector2(window.innerWidth, window.innerHeight),
  // dashArray: 0.2,
  dashArray: 2,
});

动画演示

第一个问题是虚线部分并没有完全不可见。放大后,你会注意到它。线条看起来像是被切断的,因为虚线部分重叠的区域出现在前面。

那么,为了让虚线部分真正不可见,我们将transparent属性设置为true

lineMaterial.transparent = true;

正如你所看到的,通过使虚线部分真正不可见,解决了两个问题中的一个。然而,可见部分仍然看起来像是被切断的,因为虚线在它前面。

为了防止这种遮挡问题,我们将depthTest属性设置为false

lineMaterial.depthTest = false;

我们可以改变曲线的宽度。例如,它可以逐渐变细。

为此,我们将一个函数作为setPoints()方法的第二个参数设置。

// geometry.setPoints(geometryPoints);
geometry.setPoints(geometryPoints, (p) => 1 - p);

我们可以做相反的事情,也就是说让曲线从细开始。

// geometry.setPoints(geometryPoints);
// geometry.setPoints(geometryPoints, (p) => 1 - p);
geometry.setPoints(geometryPoints, (p) => 1 - (1 - p));

最后,我们只需对场景进行一些后期处理,一切就绪!

动画演示

原文:waelyasmina.net/articles/an…