スパイラル 2
コイルを作る 2
今回は与えられたカーブにそってコイルが作られるようにしてみましょう。
今回のスクリプトでは計算にベクトルが使われています。
ベクトル無しでも同じ計算はできますが、
点の座標計算などをおこなう場合などは、
ベクトルを使用した方が計算が簡単になります。
ベクトルの詳しい解説はベクトルを参照してください。
コイルを作るスクリプト2
このスクリプトでは最初のコントロールポイントが (0, 0, 0)、最後のコントロールポイントが (10, 0, 0) でコントロールポイントの数が 4 つの NURBS カーブにそったコイルを作ります。
- 以下のプロシージャを makeSpiral4.mel と言う名前でファイルに書き込みます。
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 -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;
}
}
- で makeSpiral4.mel を読み込みます。
- Script Editor で以下のコマンドを実行します。
makeSpiral4();
スクリプトの解説
global proc makeSpiral4()
- makeSpiral4() というプロシージャーの宣言です。
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 -k 0 -k 0 -k 0 -k 1 -k 1 -k 1`;
- コイルの形を決めるためのカーブを作ります。
最初の CV が(0, 0, 0)の位置、最後(4 個目)の CV が(10.0, 0, 0)の位置です。
CV の個数が 4 個なのは、
下の $p の計算でカーブのパラメータが 0.0 から 1.0 だと仮定して計算しているからです。
このスクリプト makeSpiral4 では、
このカーブの最初と最後の CV における Y, Z 座標がともに 0 でないとコイルの最初と最後の CV がずれてしまうことに注意してください。
int $numCvs = $numLoops * 4;
- コイルになるカーブのコントロールポイントの個数を決めています。
コイル 1 まわりごとに 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 回分 for 文を実行します。
float $p = (float)$i/$numCvs;
- カーブの全体を 1.0 として $i 番目のコントロールポイントのパラメータを求めます。
$p はカーブ($curv)上で、
これからどの位置のコントロールポイントを求めようとしているかを表しています。
この値は後で $angle の計算と pointOnCurve コマンドで使用されます。
$i の前の (float) が無いと $i/$numCvs が 0 になってしまうことに注意してください。
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 に等しい時、
つまり最初と最後は特別に $uoff と $voff を 0.0 にしておきます。
これによって、for 文の中で最初に作られる CV が元のカーブの始まりと一致し、
for 文の中で最後に作られる CV が元のカーブの終りと一致します。
しかし、コイルのカーブの 1 個目の CV はすでに(0, 0, 0)に作られているので、
元のカーブの始まりが(0, 0, 0)にないと、
コイルのカーブの始点とずれてしまって、
うまくゆきません。
この問題については、下の練習で修正します。
string $poc = `pointOnCurve -constructionHistory 1 -parameter $p $curv`;
- カーブ $curv におけるパラメータ $p の位置の情報を得るコマンドです。
-constructionHistory フラグを 1 にしているので、その点における pointOnCurveInfo ノードが作られて、
その名前が $poc に代入されます。
この pointOnCurveInfo ノードを使ってカーブ上の、
その点における法線・接線などの情報を得ることができます。
$p には、最初に 0.0 が入っているので下の図の pointOnCurveInfo1 ノードには 0.0 の位置におけるカーブの情報が入っています。
pointOnCurveInfo ノードは、この pointOnCurve コマンドが実行されるたびに作られてゆきます。
下の図は 2 回目に pointOnCurve コマンドが実行された後の Hypergraph の図です。
このスクリプトでは for 文が $numCvs + 1 回実行されるので、
最終的に $numCvs + 1 個の pointOnCurveInfo ノードが作られます。
float $val[3] = `getAttr ( $poc + ".nn" )`;
-
パラメータ $p の位置のカーブ上の点の法線を求めます。
$poc の nn (normalizedNormal)アトリビュートの値を getAttr コマンドによって得ています。
vector $nv = << $val[0], $val[1], $val[2] >>;
- 法線の X, Y, Z の値をベクトルに変換します。
$nv は pointOnCurveInfo ノードの normalizedNormal アトリビュートから得た値なので、
長さ 1 のベクトルになっています。
ここでベクトル $nv を求めているのは、
以下の部分で cross コマンドの引数として与えるためと、
コイルのコントロールポイントを計算するためです。
float $val[3] = `getAttr ( $poc + ".nt" )`;
-
カーブ上のパラメータ $p の位置にある点の接線を求めます。
$poc の nt(normalizedTangent) アトリビュートの値を getAttr コマンドによって得ています。
vector $tv = << $val[0], $val[1], $val[2] >>;
- 接線の X, Y, Z の値をベクトルに変換します。
$tv は pointOnCurveInfo ノードの normalizedTangent アトリビュートから得た値なので、
長さ 1 のベクトルになっています。
ベクトル $tv を求めているのは、
以下の部分で cross コマンドの引数として与えるためです。
vector $npv = `cross $nv $tv`;
- 法線 $nv と接線 $tv の外積を求めます。
これによって法線と接線のなす平面と垂直なベクトルを求めることができます。
float $px = `getAttr ($poc + ".px")`;
- カーブ上のパラメータ $p の位置にある点の X 座標を求めます。
float $py = `getAttr ($poc + ".py")`;
- カーブ上のパラメータ $p の位置にある点の Y 座標を求めます。
float $pz = `getAttr ($poc + ".pz")`;
- カーブ上のパラメータ $p の位置にある点の Z 座標を求めます。
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 のコントロールポイントを追加します。
練習
- 上の makeSpiral4.mel を参考にして makeSpiral5.mel を作り、
カーブ $curv の名前、
ループする回数とコイルの半径を引数によって変えることができるようにしてみましょう。
また、元のカーブの始点が(0, 0, 0)の位置になくても、
コイルのカーブの始点が、
元のカーブの始点と同じ位置になるようにしてください。
コイルの半径は、カーブから CV までの距離になるので注意してください。
(プロシージャーの名前と引数)
makeSpiral5(string カーブの名前, int ループの回数, float コイルの半径)
- カーブの名前
- コイルを作るための、元カーブの名前です。
- ループの回数
- コイルが巻かれる回数です。
- コイルの半径
- 元カーブからコイルの CV までの距離です。
実際に作られるカーブの半径は、
この値より小さくなります。
(使用例)
- CV の数が 4 つの NURBS カーブを適当に作ります。
- 作ったカーブの名前を引数に与えて実行します。
カーブの名前は Channel Box または Script Editor に表示されています。
例えば、カーブの名前が curve1、
ループ回数 20、半径 2.0 なら以下のように実行します。
makeSpiral5("curve1", 20, 2.0);
参考
練習課題
Prev | Next
Home | Contents
Mail