>   >  COYOTE流テクニカルTIPS:TIPS 03:【Maya】ベクトルの活用(内積・外積・三角関数)
TIPS 03:【Maya】ベクトルの活用(内積・外積・三角関数)

TIPS 03:【Maya】ベクトルの活用(内積・外積・三角関数)

クリーク・アンド・リバー社の社内CGスタジオであり、ゲームの3DCGグラフィックス制作を中心に手がけているCOYOTE 3DCG STUDIO。本連載では、同社のTAチームによる制作に役立つ技術TIPSを紹介していく。

TEXT_山本智人 / Tomohito Yamamoto(COYOTE 3DCG STUDIO)
EDIT_三村ゆにこ / Uniko Mimura(CGWORLD)

はじめに

おはこんばんちわ。休日の昼、家族にパスタをつくったけどまったく味がしない謎物体を提供した、COYOTE 3DCG STUDIO テクニカルアーティスト(以下、TA)の山本ほっさんです。

全3回に渡って紹介するテクニカルTIPS「ノードの回転制御」。今回はシリーズの最終回です。

・ベクトルを使ったノードのBend制御(第1回
・Quaternionを使ったRoll成分の分解(第2回
・ベクトルの活用(内積・外積・三角関数)←イマココ!

ここまでお話しした中でもいくつか数学的なアプローチを紹介してきましたが、意外と数学にはグラフィカルな一面があったと思います。今回は「ベクトルの活用(内積・外積・三角関数)」と称し、ひとまず簡単なところで、ExpressionでVector型を使ったAim Constraintの再現をなぞりつつ、「数学のグラフィカルな一面」を中心に紹介していきます。

Result:結果を先に

Aim constraintをExpressionで再現するには、以下のような手順を踏みます。

①:対象のノードとAim targetの座標から対象のノード→Aim target の単位ベクトルを求める
②:①で求めたベクトルの回転前後のベクトルから、内積と三角関数を用いて回転角度を計算する
③:①で求めたベクトルの回転前後のベクトルから、外積を用いて回転軸のベクトルを計算する
④:②と③の結果をaxisとangleとして値をExpression外に出し、Quaternion経由でEuler変換
⑤:対象ノードの回転アトリビュートに接続

ExpressionのコードとNodeEditorの結果は以下の通り。

vector $Pos_targetNode = 
«argetNode.translateX,targetNode.translateY,targetNode.translateZ»;

vector $Pos_aimNode = 
«aimVector.translateX,aimVector.translateY,aimVector.translateZ»;

vector $defaultAimVector = <<1.0,0.0,0.0>>;
vector $aimVector = unit($Pos_aimNode -$Pos_targetNode);

//aim rotate
float $dotProd = dot($defaultAimVector,$aimVector);
vector $rotateAxis = cross($defaultAimVector,$aimVector);
float $rotateAngle = acosd($dotProd);

axisAngleToQuat1.inputAxisX = $rotateAxis.x;
axisAngleToQuat1.inputAxisY = $rotateAxis.y;
axisAngleToQuat1.inputAxisZ = $rotateAxis.z;
axisAngleToQuat1.inputAngle = $rotateAngle;

コードとNodeEditor上はわりとシンプルにできますね。
では、1つずつ紐解いてみましょう。


Step 00:そもそも「ベクトル」ってなに?

設計と実装を進める前に、まず「ベクトルとは何か」を少し考えてみます。3DCGで扱うベクトルとは主に「空間ベクトル」を指しており、一般的には「向き」と「長さ(大きさ)」をもつ「量」と言われます。文章解説ではいまいちワカランと思いますが、以下の図で見てみるとイメージしやすいのではないでしょうか。

Maya上のTranslateの値にあるように、3D空間上の点は「X」、「Y」、「Z」の3つの値で定義できます。この(X,Y,Z)の値を「座標」としてではなく、原点座標からの「向き」と「距離」として考えるのが「ベクトル」にあたります。

原点座標から「あっち」とか「あそこ」などと指し示すイメージにも近いかもしれませんね。


ベクトルは「足し算・引き算」ができる

そしてこの「向き」と「長さ」をもつ概念ベクトルは、お互いに「足し算・引き算」することができます。数式的に書くと......

( x, y, z ) - ( x', y', z' ) = ( x+x', y+y', z+z' )

と表し、すなわち3つの値を同時に計算できる概念というわけです。
もっと図形的に考えると......

座標平面上にある「ベクトルA」、「ベクトルB」に対しての「足し算」を考えてみます。

まず「ベクトルA」の分だけ、原点Oから点Pが移動したとします。

次に、現在の位置から追加で「ベクトルB」の分だけ点Pが移動したとします。

すると、最終的には点Pは原点Oからこのように移動したことになり......

すなわち、「ベクトルA」と「ベクトルB」の足し算は、このように表すことができるわけです。また、物理学の側面からもベクトルの足し算を考えることができます。

例えば、重たい荷物が原点にあったとして、それをAさん、Bさんがそれぞれ「ベクトルA」、「ベクトルB」分の力で各々引っ張ったとします。
すると、この原点位置にある荷物にかかる力は......

このように平行四辺形の図で考えることができ......

その平行四辺形の対角線に沿って、このような力がかかります。これもまた「ベクトルA」と「ベクトルB」の足し算の結果に等しくなります。ちなみに物理学では、このような2つの力(ベクトル)が合わさった力(ベクトル)を「合力」と呼びます。ベクトルは「数式」というより図形的・幾何学的なロジックですよね。


Step 01:対象のノードから見たAim targetへのベクトルは?

さて、Aim Constraintの話に戻りましょう。上記の例は、空間上の座標(X,Y,Z)を原点位置から見たベクトルとして考えるお話でした。では、任意の座標A(X,Y,Z)から見た、別の座標B(X',Y',Z')へのベクトルはどのように表すのでしょうか。

上記のように座標Aと座標Bの値だけでは、単に原点からのベクトルにしかなりません。対象のノードから見たAim targetへの向きを知りたいので......

欲しいのはこのベクトルです。
このベクトルを原点位置に平行移動させてくると......

こうなります。
さて、ここで気付くべきは、

この平行四辺形のイメージです。

ここのベクトルは、

ベクトルAの逆ベクトルにあたるので、つまり求めたいベクトルABは......

ベクトルB+(ーベクトルA)すなわち、ベクトル「BーベクトルA」と表すことができるわけです。ですの