[Lightwave] 2点間を曲線で繋ぐ(1) ベジエ編

はじめに

ケーブル類のモデリングやアニメーションを容易にするために、2点間を曲線で繋ぐ方法をLightWave3D 2023に追加されたProcedural Geometryで実現する方法を考えてみました。

LightWaveではおなじみのNullオブジェクトを使って始点と終点を指定し、曲線のたわみ具合は一旦固定、まずは曲線を構成するポイント位置に球(Sphere)を表示してみることにしました(このときはSpline Geometryを使う方法が、まだ分からなかった)。

chatGPTに聞いてみた

取っ掛かりとして、chatGPTに3次元ベジエ曲線の計算方法を相談。始点と終点の座標、曲線のたわみ具合と曲線の分割数を与えて曲線を計算するC言語のプログラムを提案してもらいました。

#include <stdio.h>
#include <math.h>

// 3次元ベジェ曲線の座標計算関数
void bezier_curve_3d(double x1, double y1, double z1, double x2, double y2, double z2, double bulge, int num_points, double curve_x[], double curve_y[], double curve_z[]) {
    // 制御点の計算
    double control_x = (x1 + x2) / 2 + bulge * (y2 - y1);
    double control_y = (y1 + y2) / 2 - bulge * (x2 - x1);
    double control_z = (z1 + z2) / 2 + bulge * (z2 - z1);

    // ベジェ曲線の座標計算
    for (int i = 0; i <= num_points; i++) {
        double t = (double)i / num_points;
        curve_x[i] = (1 - t) * (1 - t) * x1 + 2 * (1 - t) * t * control_x + t * t * x2;
        curve_y[i] = (1 - t) * (1 - t) * y1 + 2 * (1 - t) * t * control_y + t * t * y2;
        curve_z[i] = (1 - t) * (1 - t) * z1 + 2 * (1 - t) * t * control_z + t * t * z2;
    }
}

int main() {
    // パラメータの指定
    double x1 = 0.0, y1 = 0.0, z1 = 0.0;  // 始点
    double x2 = 10.0, y2 = 10.0, z2 = 10.0; // 終点
    double bulge = 0.5;                     // たわみ具合
    int num_points = 100;                   // 2点間のポイント数

    // ベジェ曲線の座標を格納する配列
    double curve_x[num_points + 1];
    double curve_y[num_points + 1];
    double curve_z[num_points + 1];

    // ベジェ曲線の座標を計算
    bezier_curve_3d(x1, y1, z1, x2, y2, z2, bulge, num_points, curve_x, curve_y, curve_z);

    // 結果を表示
    printf("3D Bezier Curve Points:\n");
    for (int i = 0; i <= num_points; i++) {
        printf("Point %d: (%f, %f, %f)\n", i, curve_x[i], curve_y[i], curve_z[i]);
    }

    return 0;
}

これを参考にしてノードで処理を組んでいく。

Procedural Geometryノードの構成

chatGPTが提案してくれたプログラムに従って、カーブのたわみは始点と終点の中間にY座標を少し下げた位置に制御点を設けることで調整。「始点」「制御点」「終点」の3つの点からベジエ曲線を計算することにした。

全体像です。この中ではFor Loopノードでの繰り返しが若干わかりにくく、付属のドキュメントやサンプルシーンを読み解きつつ、なんとか組み上げました。

ベジエを計算してる部分のノード。X,Y,Zで同じ計算させたいのでCompoundでまとめています。整理してないのでぐちゃぐちゃで見づらい。

プログラムの14行目の計算をノードに置き換えています(X,Y,Z入力される値が変わるだけで計算方法は同じ)。

主なポイント

  • Item Infoノードで始点と終点のアイテムを指定して位置を取得
  • Lerp Vectorで始点と終点の中間位置を計算(制御点の位置)
  • Vector Scalarノードで位置をX,Y,Zに分解
  • For Loop
    • 繰り返す値の範囲を指定(今回は0~20)
    • Deltaから0.0~1.0の範囲が繰り返す値の範囲に応じて都度出力される
    • Loopには繰り返す処理を接続
    • Resultから最終的なモノが出力される
  • CompoundノードでPrimitive Geometry(Sphere)の位置を計算
  • 位置はX,Y,Z個別(Scalar)で計算しているのでMake Vectorでベクトルにする
  • Add Geometryでジオメトリコレクションへ追加

詳細はシーンファイルを御覧ください。

ダウンロード

シーンファイル(.lws)

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です