スパイラル 2

コイルを作る 2

今回は与えられたカーブにそってコイルが作られるようにしてみましょう。

今回のスクリプトでは計算にベクトルが使われています。
ベクトル無しでも同じ計算はできますが、 点の座標計算などをおこなう場合などは、 ベクトルを使用した方が計算が簡単になります。
ベクトルの詳しい解説はベクトルを参照してください。

コイルを作るスクリプト2

このスクリプトでは最初のコントロールポイントが (0, 0, 0)、最後のコントロールポイントが (10, 0, 0) でコントロールポイントの数が 4 つの NURBS カーブにそったコイルを作ります。

  1. 以下のプロシージャを 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;
    	}
    }
    
  2. File → Source Script で makeSpiral4.mel を読み込みます。
  3. Script Editor で以下のコマンドを実行します。
    makeSpiral4();
    [image of makeSpiral4.mel]

スクリプトの解説

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 になってしまうことに注意してください。
[image of prameter $p]
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 の位置におけるカーブの情報が入っています。
[Hypergraph 上の pointOnCurveInfo]
pointOnCurveInfo ノードは、この pointOnCurve コマンドが実行されるたびに作られてゆきます。
下の図は 2 回目に pointOnCurve コマンドが実行された後の Hypergraph の図です。
[2 個目の pointOnCurveInfo]
このスクリプトでは 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 の外積を求めます。
これによって法線と接線のなす平面と垂直なベクトルを求めることができます。
[image of cross product]
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;
コイルのコントロールポイントの位置を表すベクトルを計算します。
[image of $vec]
curve -append -p ($vec.x) ($vec.y) ($vec.z) $crv;
カーブ($crv)に $vec.x$vec.y$vec.z のコントロールポイントを追加します。

練習

参考

練習課題


Prev | Next
Home | Contents
Mail