はじめに

ケーブル類のモデリングやアニメーションを容易にするために、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でジオメトリコレクションへ追加
詳細はシーンファイルを御覧ください。