今回は与えられたカーブにそってコイルが作られるようにしてみよう。
少し複雑なスクリプトなので、心して見て欲しい。
使用例のスクリプトではベクトルという新しいものが使われているので難しい部分があるかもしれないが、ベクトルを使用するとスクリプトが簡単でわかりやすくなるので覚えておくと良い。
(MELコマンドにはベクトルを引数にとるコマンドも多い)
ベクトルとは簡単にいえば、いくつかの数を並べたものである。
MELでは3つの数(変数でも良い)を<< 1, 2, 3 >>のように<<と>>の間に並べる。
このベクトルを使うことによって座標の計算などを簡単に表すことができるようになる。
例えばX, Y, Z座標に2を掛ける計算は以下のようになる。
$x2 = 2 * $x1;
$y2 = 2 * $y1;
$z2 = 2 * $z1;
$v2 = 2 * $v1;
$v1 = << 4, 2, 1 >>だとすると$v2 = << 8, 4, 2 >>になる。
ベクトルは以下のように矢印で表されることが多い。
このスクリプトでは最初のコントロールポイントが(0, 0, 0)、最後のコントロールポイントが(X, 0, 0)でコントロールポイントの数が4つのNURBSカーブにそったコイルを作る。
今回のスクリプトは長いので効率良く作るようにしよう。
前回作ったスクリプト(makeSpiral1.mel)と半分くらいは同じなので、それをもとにするのが良いだろう。
似ている行はviのコピーの機能を使ってコピーしてから異なるところだけ書き換えるようにしよう。
global proc makeSpiral4()
{
int $i;
int $numLoops = 10;
string $curv = `curve -degree 3 -p 0 0 0 -p 2.0 0 -6.0 -p 8.0 0 -4.0 -p 10.0 0 -0.0 -k 0 -k 0 -k 0 -k 1 -k 1 -k 1`;
int $numCvs = $numLoops * 4;
string $crv = `curve -degree 3 -p 0 0 0 -k 0 -k 0 -k 0`;
for( $i = 0; $i <= $numCvs; $i++ )
{
float $p = (float)$i/$numCvs;
float $angle = $p * $numLoops * 6.28;
float $uoff = sin($angle);
float $voff = cos($angle);
if( $i == 0 || $i == $numCvs )
{
$uoff = 0;
$voff = 0;
}
string $poc = `pointOnCurve -constructionHistory 1 -parameter $p $curv`;
float $val[3] = `getAttr ( $poc + ".nn" )`;
vector $nv = << $val[0], $val[1], $val[2] >>;
float $val[3] = `getAttr ( $poc + ".nt" )`;
vector $tv = << $val[0], $val[1], $val[2] >>;
vector $npv = `cross $nv $tv`;
float $px = `getAttr ($poc + ".px")`;
float $py = `getAttr ($poc + ".py")`;
float $pz = `getAttr ($poc + ".pz")`;
vector $pv = << $px, $py, $pz >>;
$vec = $pv + $uoff * $npv + $voff * $nv;
curve -append -p ($vec.x) ($vec.y) ($vec.z) $crv;
}
}
int $numLoops = 10;
ループする回数を決める変数。
string $curv = `curve -degree 3 -p 0 0 0 -p 2.0 0 -6.0 -p 8.0 0 -4.0 -p 10.0 0 -0.0 -k 0 -k 0 -k 0 -k 1 -k 1 -k 1`;
コイルの形を決めるためのカーブ。
int $numCvs = $numLoops * 4;
カーブのコントロールポイントの個数を決めている。
string $crv = `curve -degree 3 -p 0 0 0 -k 0 -k 0 -k 0`;
NURBSカーブを作って、その名前を$crvに代入している。
for( $i = 0; $i <= $numCvs; $i++ )
$iを0 から$numCvsまで$numCvs + 1 回分ループを実行する。
float $p = (float)$i/$numCvs;
カーブの全体を1.0として$i番目のコントロールポイントのパラメータを求める。
float $angle = $p * $numLoops * 6.28;
コントロールポイントを計算するために現在の角度を計算している。
float $uoff = sin($angle);
コントロールポイントの計算のための値をsin関数によって求める。
float $voff = cos($angle);
コントロールポイントの計算のための値をcos関数によって求める。
if($i == 0 || $i == $numCvs)
{
$uoff = 0.0;
$voff = 0.0;
}
$iが0または$numCvsに等しい時(最初と最後)は特別にY,Z座標は0.0にする。
string $poc = `pointOnCurve -constructionHistory 1 -parameter $p $curv`;
カーブ$curvにおけるパラメータ$pの位置の情報を得るコマンド。
(pointOnCurveInfo ノードを返す)
float $val[3] = `getAttr ( $poc + ".nn" )`;
カーブ上の点の法線を求める。
(パラメータ$pの位置)
vector $nv = << $val[0], $val[1], $val[2] >>;
法線のX, Y, Zの値をベクトルに変換する。
($nvは長さ1のベクトルである)
float $val[3] = `getAttr ( $poc + ".nt" )`;
カーブ上の点の接線を求める。
(パラメータ$pの位置)
vector $tv = << $val[0], $val[1], $val[2] >>;
接線のX, Y, Zの値をベクトルに変換する。
($tvは長さ1のベクトルである)
vector $npv = `cross $nv $tv`;
法線と接線の外積を求める。
float $px = `getAttr ($poc + ".px")`;
カーブ上の点のX座標を求める。
(パラメータ$pの位置)
float $py = `getAttr ($poc + ".py")`;
カーブ上の点のY座標を求める。
(パラメータ$pの位置)
float $pz = `getAttr ($poc + ".pz")`;
カーブ上の点のZ座標を求める。
(パラメータ$pの位置)
vector $pv = << $px, $py, $pz >>;
座標のX, Y, Zの値をベクトルに変換する。
$vec = $pv + $uoff * $npv + $voff * $nv;
コイルのコントロールポイントの位置を表すベクトルを計算。
curve -append -p ($vec.x) ($vec.y) ($vec.z) $crv;
カーブ($crv)に$vec.x、$vec.y、$vec.zのコントロールポイントを追加する。