スパイラル 3

コイルを作る 3

今回はエクスプレッションを利用して、 元になるカーブを動かすと、 コイルも同様に動くようにしてみましょう。
これによって、 元カーブをアニメーションさせることによって、 コイルも自動的にアニメーションさせることができるようになります。

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

エクスプレッションの式が複雑なので注意してみてください。

  1. 以下のプロシージャを makeSpiral7.mel と言う名前でファイルに書き込みます。
    global proc makeSpiral7()
    {
    	int $i;
    	float $numLoops = 10;
    	string $curv = `curve -d 3 -p 0 0 0 -p 3.0 0 -4.0 -p 7.0 0 -7.0
    			-p 13.0 0 -5.0 -p 17.0 0 -2.0 -p 19.0 0 0.0
    			-k 0 -k 0 -k 0 -k 1 -k 2 -k 3 -k 3 -k 3`;
    
    	int $numCvs = $numLoops * 4;
    	float $min = getAttr ($curv + ".min");
    	float $max = getAttr ($curv + ".max");
    	string $crv = `curve -degree 3 -p 0 0 0 -k 0 -k 0 -k 0`;
    	for($i = 0; $i < $numCvs; $i++)
    	{
    		curve -append -p ((float)$i) 0 0 $crv ;
    	}
    	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.0;
    			$voff = 0.0;
    		}
    		$p = $min + ($max - $min) * $p;
    		string $poc = `pointOnCurve -constructionHistory 1 -parameter $p $curv`;
    		string $expcom = ( "vector $nv = <<nnx, nny, nnz>>;\n"
    			+ "vector $tv = <<ntx, nty, ntz>>;\n"
    			+ "vector $npv = `cross $nv $tv`;\n"
    			+ "vector $pv = <<px, py, pz>>;\n"
    			+ "$vec = $pv + " + $uoff + " * $npv + " + $voff + " * $nv;\n"
    			+ $crv + ".cp[" + $i + "].xv = $vec.x;\n"
    			+ $crv + ".cp[" + $i + "].yv = $vec.y;\n"
    			+ $crv + ".cp[" + $i + "].zv = $vec.z;\n" );
    		expression -o $poc -s $expcom;
    	}
    }
    
  2. File → Source Script で makeSpiral7.mel を読み込みます。
  3. Script Editor で以下のコマンドを実行します。
    makeSpiral7();
    [image of makeSpiral7.mel]
  4. 元カーブを適当にアニメーションさせると、コイルもそれにつれてアニメーションします。
    アニメーション実行例

スクリプトの解説

global proc makeSpiral4()
makeSpiral4() というプロシージャーの宣言です。
int $numLoops = 10;
ループする回数を決める変数に、 とりあえずの値として 10 を代入しています。
string $curv = `curve -d 3 -p 0 0 0 -p 3.0 0 -4.0 -p 7.0 0 -7.0 -p 13.0 0 -5.0 -p 17.0 0 -2.0 -p 19.0 0 0.0 -k 0 -k 0 -k 0 -k 1 -k 2 -k 3 -k 3 -k 3`;
コイルの形を決めるためのカーブです。
int $numCvs = $numLoops * 4;
コイルを作るためにコントロールポイントの個数を決めています。
コイル 1 まわりごとに 4 個のコントロールポイントを作ります。
float $min = getAttr ($curv + ".min");
元になるカーブのパラメータの最小値を $min に代入します。
float $max = getAttr ($curv + ".max");
元になるカーブのパラメータの最大値を $max に代入します。
これらのアトリビュート(min, max)によって、 元になるカーブが編集されていても、 コントロールポイントの個数がいくつになっていても、 最初から最後までコイルを作ることができます。
string $crv = `curve -degree 3 -p 0 0 0 -k 0 -k 0 -k 0`;
コイルになる NURBS カーブを作って、その名前を $crv に代入します。
for($i = 0; $i < $numCvs; $i++)
{
  curve -append -p ((float)$i) 0 0 $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 にしておくと、 なぜそうなるかというとエクスプレッションの式で、
$vec = $pv + " + $uoff + " * $npv + " + $voff + " * $nv;
の部分が
$vec = $pv + 0.0 * $npv + 0.0 * $nv;
となって、結局
$vec = $pv;
となるからです。
$p = $min + ($max - $min) * $p;
元のカーブの最小値・最大値によって $p を計算し直します。
$p は 0.0 から 1.0 の間の値ですが、 それを比率を保ったまま $min から $max までの値に修正しています。
[古い $p と新しい $p の関係]
string $poc = `pointOnCurve -constructionHistory 1 -parameter $p $curv`;
カーブ $curv におけるパラメータ $p の位置の情報を得るコマンドです。 -constructionHistory フラグを 1 にしているので、その点における pointOnCurveInfo ノードが作られて、 その名前が $poc に代入されます。
この pointOnCurveInfo ノードを使ってカーブ上の、 その点における法線・接線などの情報を得ることができます。
$p には、最初に $min の値が入っているので下の図の pointOnCurveInfo1 ノードには $min の位置におけるカーブの情報が入っています。
[Hypergraph 上の pointOnCurveInfo]
pointOnCurveInfo ノードは、この pointOnCurve コマンドが実行されるたびに作られてゆきます。
下の図は 2 回目に pointOnCurve コマンドが実行された後の Hypergraph の図です。
[2 個目の pointOnCurveInfo]
このスクリプトでは for 文が $numCvs + 1 回実行されるので、 最終的に $numCvs + 1 個の pointOnCurveInfo ノードが作られます。
string $expcom = ( "vector $nv = <<nnx, nny, nnz>>;\n"
  + "vector $tv = <<ntx, nty, ntz>>;\n"
  + "vector $npv = `cross $nv $tv`;\n"
  + "vector $pv = <<px, py, pz>>;\n"
  + "$vec = $pv + " + $uoff + " * $npv + " + $voff + " * $nv;\n"
  + $crv + ".cp[" + $i + "].xv = $vec.x;\n"
  + $crv + ".cp[" + $i + "].yv = $vec.y;\n"
  + $crv + ".cp[" + $i + "].zv = $vec.z;\n" );
アニメーションのために、 エクスプレッションの式を組み立てています。
変数 $poc$uoff$voff$crv$i と文字列(白抜き文字部分)を組み合わせて、 いくつかの式を組み立てていきます。
これらの変数と文字列は + によって結合されて、 ひとつの文字列となり $expcom に代入されます。
これらの式の意味は以下の通りになります。 (適当に +, ", (, ) などを省略してあります)
"vector $nv = <<nnx, nny, nnz>>;\n"
pointOnCurveInfo ノード($poc)のアトリビュート(nnx, nny, nnz)から、 カーブ上のパラメータ $p の位置の点の法線ベクトルを求めます。
エクスプレッション内において、 getAttr コマンドを使用しないでもアトリビュートの値を得ることができることに注意してください。
なお、ノードの名前が変更された場合に対応できないので、 エクスプレッションでは getAttr コマンドは使わないでください。
"vector $tv = <<ntx, nty, ntz>>;\n"
pointOnCurveInfo ノード($poc)のアトリビュート(ntx, nty, ntz)から、 カーブ上のパラメータ $p の位置のカーブ上の点の接線ベクトルを求めます。
法線と同じ理由で XYZ 座標ごとに別々に求めて変数に代入しておきます。
"vector $npv = `cross $nv $tv`;\n"
法線と接線の外積を求めます。
これによって法線と接線のなす平面と垂直なベクトルを求めることができます。
[image of cross product]
"vector $pv = <<px, py, pz>>;\n"
pointOnCurveInfo ノード($poc)のアトリビュート(px, py, pz)から、 カーブ上のパラメータ $p の位置のカーブ上の点の座標をベクトルとして求めます。
"$vec = $pv + " + $uoff + " * $npv + " + $voff + " * $nv;\n"
コイルのコントロールポイントの位置を表すベクトルを計算します。
[image of $vec]
$crv + ".cp[" + $i + "].xv = $vec.x;\n"
$crv + ".cp[" + $i + "].yv = $vec.y;\n"
$crv + ".cp[" + $i + "].zv = $vec.z;\n" );
コイルのカーブにおける $i 番目のコントロールポイントの座標に $vec の値を代入します。
なお、各文字列の最後に入っている \n はエクスプレッションの式を表示した時に、 見やすくするためのもので無くても実行に支障はありません。
expression -o $poc -s $expcom;
pointOnCurveInfo ノード($poc)に、 文字列 $expcom に入っている式によってエクスプレッションを定義します。
この expression コマンドは for 文によって $numCvs + 1 回実行されるので、 エクスプレッションノードが $numCvs + 1 個作られます。

Tips

makeSpiral7 によって作られるエクスプレッションの式は具体的にどんな式になっているのでしょうか。 それを確かめるためには以下のコマンドを実行してみてください。

expression -q -s expression1;

実行すると expression1 というエクスプレッションノードに定義されている式が Script Editor のヒストリーウインドウに表示されるはずです。

[expression コマンドの実行例]

makeSpiral7 では計 41 個のエクスプレッションが、 他にエクスプレッションを定義していない限り、expression1 〜 expression41という名前で作られているはずなので、 expression1 以外のエクスプレッションノードも同様に表示して較べてみてください。

練習

参考

練習課題


Prev | Next
Home | Contents
Mail