日本でハリウッドVFXを制作! 「経産省アイディアボックス」 結果:  
●まとめエントリはこちら ●FAQ ●お問い合わせは左のメールフォームから

2009年5月12日火曜日

二つのオブジェクト間の距離を求める (1)

先日のmagコマンドを使って、二つのオブジェクトを選択し、そのオブジェクト間の距離を表示するスクリプトを実際に作ってみたい。

このスクリプトのアルゴリズムは
0)シーンビューでマウスを使い、二つのオブジェクトを選択
1)各オブジェクトの名称を得る
2)各オブジェクトの座標値を得る。
3)vector型に格納する。
4)二つのオブジェクトのvectorの差を求める
5)magコマンドで大きさを得る。

となり、「2~3」のステップでは二種類の方法がある。
ひとつはgetAttrコマンドを使う方法、もう一つはxformコマンドを使う方法。



ここでは、まずgetAttrを使う方法を見ていきたい。

--------------------
1)オブジェクトの名称を得る:
ls -sl を使えば「現在選択しているオブジェクトの名称」を返してくる。
これを変数へ格納しておけばよいのだが、二つのオブジェクトの名称を一度に格納し、後からそれぞれ別に取り出してその名称を使用する必要がある。
これを行うには「配列」を使用する。

名称は文字列なので、データ型は「string」になる。
string $name[] = `ls -sl;

printコマンドで、$nameのそれぞれの要素を確認。(\nを付けて改行し、見やすくしてある)
{ string $name[] = `ls -sl`; print ($name[0]+"\n"); print ($name[1]+"\n"); }

--------------------
2)各オブジェクトの座標値を得る。

getAttrコマンドを使う方法
これはlearning Maya pg110に掲載されている方法。
座標値イコール、translateX,Y,Zなので、getAttrを使用する場合はX,Y,Zのそれぞれを別のコマンドで取得する必要がある。
getAttr $name[0].tx
と入力してみたが、
// エラー: Syntax error //

配列名(または変数名)はそのままでは、一つの文字列の一部としてつかうことはできないのは、
プリント文でわかっていたつもりだったがついうっかりしていた。

getAttr ($name[0] + ".tx");
これでエラーはでないが、値が正確に保管されているのかどうかはわからないので
返り値を変数へ代入してから、printで表示した。
ちなみに返り値は小数点数なので、変数のタイプは「float」になる。

{ string $name[] = `ls -sl`; float $obj1X = getAttr ($name[0] + ".tx"); print ($obj1X + "\n"); }

これでちゃんと座標値xの値が表示されたので正常に動いていることは確認とれた。

つぎにこれをY座標、Z座標の値にも使い、一つ目のオブジェクト(OBJ1)と二つ目のオブジェクト(OBJ2)の両方の値を取得できるように展開する。
コピペで変数名と配列のID番号を変えるだけで終わり。
{
string $name[] = `ls -sl`;

float $obj1X = getAttr ($name[0] + ".tx");

float $obj1Y = getAttr ($name[0] + ".ty");
float $obj1Z = getAttr ($name[0] + ".tz");

float $obj2X = getAttr ($name[1] + ".tx");

float $obj2Y = getAttr ($name[1] + ".ty");
float $obj2Z = getAttr ($name[1] + ".tz");

print ($obj1X + "\n");

print ($obj1Y + "\n");
print ($obj1Z + "\n");

print ($obj2X + "\n");
print ($obj2Y + "\n");
print ($obj2Z + "\n");
}


--------------------
3)値をvector型<< >>に格納する。
ここからは得られた数字を、後でmagコマンドで使用するためにまとめていく手順。

ベクトルを宣言し、XYZの値に数字の代わりに先ほどの変数を書いておけばよいので
vector $obj1Vec = <<$obj1X, $obj1Y,$obj1Z>>;
となる。


{
string $name[] = `ls -sl`;

float $obj1X = getAttr ($name[0] + ".tx");
float $obj1Y = getAttr ($name[0] + ".ty");
float $obj1Z = getAttr ($name[0] + ".tz");

float $obj2X = getAttr ($name[1] + ".tx");
float $obj2Y = getAttr ($name[1] + ".ty");
float $obj2Z = getAttr ($name[1] + ".tz");

vector $obj1Vec = <<$obj1X, $obj1Y,$obj1Z>>;
vector $obj2Vec = <<$obj2X, $obj2Y,$obj2Z>>;

print ($obj1Vec + "\n");
print ($obj2Vec + "\n");
}


--------------------
4)二つのオブジェクトのvectorの差を求める

vector $distVec = $obj1Vec - $obj2Vec;
print ($distVec + "\n");

これを上記のスクリプトに追加、ちゃんと差のvectorが表示された。
ちなみに当たり前のことだが、選択する順番を変えると値のマイナスとプラスが逆になる。


--------------------
5)magコマンドで大きさを得る。

これは簡単。
mag $distVec:
の返り値をfloatタイプの変数へ代入してやればよい。

float $dist = mag $distVec;
しかしここで問題発生...。

// エラー: float $dist = mag $distVec; //
// エラー: Maya オブジェクト "mag" の使用は無効です。 //


そこでlearning Mayaを参考にして()でくくってみたが、うまくいかない。

// エラー: float $dist = (mag $distVec); //
// エラー: Maya オブジェクト "mag" の使用は無効です。 //


ヘルプでは、
mag <<1,2,3>>;
の形式ということになっているが、変数を使うときのことまでは書いてない。

LearningMayaの「変数へコマンドの結果を代入する(p97)」のページを見てみると
コマンドの返り値を、変数へ代入するときは3つの方法がある。
1)バッククオーテーションを使う方法   : `command`
2)evalコマンドを使う方法         :eval(command)
3)括弧を使ってコマンドを実行する方法 :command (Arguments)
ちなみにArgumentsとは手続きやサブルーチンのこと。

このうち、evalコマンドを使う方法を試してみたがうまくいかない。
// エラー: float $dist = eval(mag $distVec); //
// エラー: Maya オブジェクト "mag" の使用は無効です。 //


しかたなくバッククオーテーションを使う方法を試してみたらうまくいった。

{
string $name[] = `ls -sl`;

float $obj1X = getAttr ($name[0] + ".tx");
float $obj1Y = getAttr ($name[0] + ".ty");
float $obj1Z = getAttr ($name[0] + ".tz");

float $obj2X = getAttr ($name[1] + ".tx");
float $obj2Y = getAttr ($name[1] + ".ty");
float $obj2Z = getAttr ($name[1] + ".tz");

vector $obj1Vec = <<$obj1X, $obj1Y,$obj1Z>>;
vector $obj2Vec = <<$obj2X, $obj2Y,$obj2Z>>;

vector $distVec = $obj1Vec - $obj2Vec;
float $dist = `mag $distVec`;

print ($dist + "\n");

}


それから括弧を使ってコマンドを実行する方法もうまくいった。
float $dist = mag ($distVec);


なぜかevalコマンドを使う方法だけ、うまく機能しなかったが、原因は現時点ではわからなかった。


--------------------
6)動作を確認

1)二つのオブジェクトを原点以外の場所へ移動する。Tx,Tyは同じ距離にし、Tzのみを決められた量(たとえばobj1は1.2、obj2は10.2)だけの差(ここでは10)をつけておく。

2)上記のステップ4までのスクリプトを実行する。
その二つのvectorの差が表示されるが、xとyが同じ値なので差はゼロとなりzの値のみが10となる。(例: 0,0,10)

3)そして最後のスクリプトを実行すると二つのオブジェクトの直線距離が表示される。
このとき先ほどの2のtzの値と一致するはずである。

4)それぞれのオブジェクトを任意に移動して離してみる、距離は大きくなるはず。

5)逆に近づけてみる。距離は小さくなる。

6)二つのオブジェクトを同時に選択して移動(world)する。同じ距離を移動するだけなので二つのオブジェクト間の距離は変わらない。

7)二つのオブジェクトの左右、上下など位置関係を入れ替えてみる。 このスクリプトでは二つのオブジェクトの距離を求めるだけなので、値は常時プラス値で、マイナスにはならない。


--------------------
このスクリプトで「二つのオブジェクト間の距離」を利用して別のオブジェクトやシェーダーなどのアニメーションのトリガーとして利用できる。

少し、応用例を考えてみた。
オブジェクトが近づいたことを認識させる。(センサー的な働き)
オブジェクトがある対象に近づいくにつれて色を変える。
オブジェクトがある対象に一定の距離から近づかないようにする。(パーティクルの回避行動)
あるオブジェクトから一定の距離以上に離れないようにする。
(ロープなどのアニメーションに使えるか?)
あるオブジェクトから一定の距離離れたことを認識させる。

といったことが可能、当然それらを実現するには、まだいろいろな事が必要になる。
でもとりあえず、センサーのような働きをする部品を作ることができたことはうれしい。

 

0 件のコメント:

コメントを投稿