THREE.MeshLineで、ヌルヌル動く線を作ろう!

Three.js

線を使ったアニメーションは、流れ星や紙吹雪、風の動きなど、さまざまなモチーフの表現をより豊かにしてくれます。

今回はTHREE.MeshLineを使い、リボンのように滑らかに線が動くアニメーションを作る方法を、5つのデモとともにご紹介します。オリジナルのアニメーションを作る際は、ぜひ参考にしてみてください。

THREE.MeshLineとは

筆者は2年前から、Jaume Sanchez EliasがThree.js用に作成したライブラリ『THREE.MeshLine』を使用して、WebGLでヌルヌルと動く線を作りはじめました。

THREE.MeshLineの特徴は、Three.jsが長年抱えてきた「線の幅が変更できない」という問題に取り組んでいる点にあります。MeshLineは、幅のパラメーターをサポートしていないGL_LINEメソッドのかわりに、ビルボードを使った三角形ストリップでカスタムジオメトリを作成しています。

リボンのような線にはユニークな魅力があります。また太い線を作る際によく使用されるTubeGeometryより、頂点が少ないのも特徴のひとつです。

MeshLineにアニメーションをつけよう

THREE.MeshLineに唯一欠けているのが、各フレームのジオメトリを再構築することなく、線にアニメーションをつける機能です。

SVGラインアニメーションの仕組みに基づいて、シェーダーを介してアニメーションをつけた破線を直接視覚化するために、MeshLineMaterialに3つの新しいパラメータを追加しました。

  • DashRatio:表示されているものと表示されていないものの比率(〜0:より表示される、〜1:より表示されない)
  • DashArray:破線の長さとそのスペース(0 == 破線なし)
  • DashOffset:破線がはじまる位置

これらのパラメーターを使用するとSVGパスと同じく、トレースされた線全体にアニメーションをつけられます。

以下はMeshLineを作成してアニメーションをつける方法の例です。

  // Build an array of points
  const segmentLength = 1;
  const nbrOfPoints = 10;
  const points = [];
  for (let i = 0; i < nbrOfPoints; i++) {
    points.push(i * segmentLength, 0, 0);
  }

  // Build the geometry
  const line = new MeshLine();
  line.setGeometry(points);
  const geometry = line.geometry;

  // Build the material with good parameters to animate it.
  const material = new MeshLineMaterial({
    transparent: true,
    lineWidth: 0.1,
    color: new Color('#ff0000'),
    dashArray: 2,     // always has to be the double of the line
    dashOffset: 0,    // start the dash at zero
    dashRatio: 0.75,  // visible length range min: 0.99, max: 0.5
  });

  // Build the Mesh
  const lineMesh = new Mesh(geometry, material);
  lineMesh.position.x = -4.5;

  // ! Assuming you have your own webgl engine to add meshes on scene and update them.
  webgl.add(lineMesh);

  // ! Call each frame
  function update() {
    // Check if the dash is out to stop animate it.
    if (lineMesh.material.uniforms.dashOffset.value < -2) return;

    // Decrement the dashOffset value to animate the path with the dash.
    lineMesh.material.uniforms.dashOffset.value -= 0.01;
  }

すると、このようなアニメーションが完成します。

meshline-1

オリジナルの線を作ってみよう

ここまでで、線にアニメーションをつける方法がわかりましたね。

次は線の形をカスタマイズしてみましょう。

SplineCurveまたはCatmullRomCurve3を使用する

配置されている点の配列をなめらかにしてくれる、SplineCurveもしくはCatmullRomCurve3を使ってみましょう。流れるような曲線を作り、それらの長さ・方向・動きなどをコントロールするのにぴったりです。

先ほど作った線に、動きを追加してみましょう。

 const segmentLength = 1;
  const nbrOfPoints = 10;
  const points = [];
  const turbulence = 0.5;
  for (let i = 0; i < nbrOfPoints; i++) {
    // ! We have to wrapped points into a THREE.Vector3 this time
    points.push(new Vector3(
      i * segmentLength,
      (Math.random() * (turbulence * 2)) - turbulence,
      (Math.random() * (turbulence * 2)) - turbulence,
    ));
  }

次にジオメトリを作成する前に、クラスのうちひとつを使用して線の配列をなめらかにします。

 // 2D spline
  // const linePoints = new Geometry().setFromPoints(new SplineCurve(points).getPoints(50));

  // 3D spline
  const linePoints = new Geometry().setFromPoints(new CatmullRomCurve3(points).getPoints(50));

  const line = new MeshLine();
  line.setGeometry(linePoints);
  const geometry = line.geometry;

すると、以下のような滑らかな曲線が完成します!

meshline-2

2DならSplineCurveがおすすめ

おすすめは、パフォーマンスがよく、さまざまなケースの曲線を作るのに十分な機能を備えているSplineCurveです。

ただし、3D(X・Y・Z軸)を考慮にいれているCatmullRomCurve3に対して、SplineCurveがなめらかにできるのは2D(X・Y軸)に限られるという点には注意しましょう。

以下の作品もSplineCurveで作られています。

meshline-3 meshline-4

Raycastingを使う

THREE.MeshLineの例では、シーンに既に存在するMeshをRaycasterを使ってスキャンするというテクニックが使われています。

この方法を使うと、オブジェクトの形に沿った線を作れるのです。

const radius = 4;
  const yMax = -4;
  const points = [];
  const origin = new Vector3();
  const direction = new Vector3();
  const raycaster = new Raycaster();

  let y = 0;
  let angle = 0;
  // Start the scan
  while (y < yMax) {
    // Update the orientation and the position of the raycaster
    y -= 0.1;
    angle += 0.2;
    origin.set(radius * Math.cos(angle), y, radius * Math.sin(angle));
    direction.set(-origin.x, 0, -origin.z);
    direction.normalize();
    raycaster.set(origin, direction);

    // Save the coordinates raycsted.
    // !Assuming the raycaster cross the object in the scene each time
    const intersect = raycaster.intersectObject(objectToRaycast, true);
    if (intersect.length) {
      points.push(
        intersect[0].point.x,
        intersect[0].point.y,
        intersect[0].point.z,
      );
    }
  }

この方法は、Boreal Skyのデモにも採用されています。objectToRaycastを作成するためのジオメトリとして、ここでは球体パーツを使用しました。

meshline-5

おわりに

本記事では、MeshLineにアニメーションをつけるのに十分なツールをご紹介しました。

今回ご紹介した内容の多くは、ライブラリの例を参考にしています。みなさんもThree.jsのライブラリ『THREE.MeshLine』を研究し、オリジナルの線を作ってみてください!

(原文:Jérémie Boulay 翻訳:Asuka Nakajima)

 

あわせて読みたい!▼

SHARE

RELATED

  • お問い合わせ
  • お問い合わせ
  • お問い合わせ