2014年12月31日水曜日

Maxscript その17 「3d変換行列(3D Transform Matrix) matrix3」

ここでは3D変換行列(3d Transform Matrix)の基本的な操作について少しだけ、ザックリと触れたいと思う。

3D変換マトリックスは何かというと、3Dで扱うオブジェクトの変換=移動・回転・スケールの情報らしい。それが、どのようなものなのか理解しようとすると、それはそれは(僕にとって非常に)高度な数学の知識を必要とし、理解するのが難しい。


ここでは3D変換マトリックスをシステムと捉え、それを使った基本的なトランスフォームの操作を見ていってみたいと思う。誰か知らないけど、3Dの変換を管理する素晴らしいシステムを作ってくれた。その基本的な使い方と概念。


maxscriptでは <ノード>.transformとすることで3D変換マトリックスの数値を取得/設定できるようだ。





取得した値はmatrix3という値になっており、ワールド座標基準の4つのベクトル情報を持つ。



matrix3 X軸 Y軸 Z軸 位置(オフセット)



となっている。何も操作していない状態だと以下のようになる。






X軸方向のベクトルの長さを2倍にすると次のようになる。




x,y,z,positionをコントロールするポイントを作って、各位置情報をteapotのトランスフォームに値を渡してあげるような仕組みを作ってみた。変化が分かりやすい。




4つのベクトルを使って、移動回転スケール(スキュー)が表現出来るようだ。凄いっすね・・・。

数値の説明は終わり。水色の数値から直感的に色々イメージするのは非常に難しいため、基本的にはmatrix3の数値は見ない。考えない。



matrix3値を操作するための様々な関数が用意されているが、ここでは割愛。詳しく知りたい人はscriptリファレンスの「matrix3」の項目を見て下さい。



<3D変換行列の演算 変換の継承>

リファレンスによると演算子は



演算子

+

-

*
as


とあるが、ここでは乗算(掛け算)のみ見てみようと思う。3D変換行列の基本的な演算は乗算になるようだ。


原点にあるAの変換(移動回転スケールがデフォルト値)をBに持って行く計算



Bの変換行列を取得してAの変換行列に掛け算してあげる事で、Aの変換がBの変換と等しくなる。

何も変換していないマトリックスは

matrix3 1

(matrix3 [1,0,0] [0,1,0] [0,0,1] [0,0,0])

として取得する事も可能なようだ。

$.transform = matrix3 1

で、変換をリセット出来ると思う。

トランスフォームの継承/親子関係(ペアレント)
3Dのオブジェクトのリンク(ペアレント=親子関係)の計算は基本的にはこの原理になっているようだ。

ザックリな感じであれですが、AとBのトランスフォームを掛け算した値をCに渡すと、CのトランスフォームはAとBのトランスフォームを継承した値になるようだ。いわゆる親子関係(リンク、ペアレント、コンストレイント)


だたし、掛け算する順番を変えると結果が異なるので注意が必要なようだ。

Bのトランスフォーム * Aのトランスフォーム → BがAの子の時のトランスフォーム
Aのトランスフォーム * Bのトランスフォーム → AがBの子の時のトランスフォーム

複数のペアレント構造を計算する場合も、同じ計算手順で。


Bから原点に戻す変換行列の求め方

考え方が非常に良く似ているので、ベクトルの操作の基本を見てみる。
教えて頂いたMark代表取締役 犬童さんに感謝

BからAのベクトルを求めたい時、AのベクトルからBのベクトルを引き算する事で、BからAのベクトルが取得出来る。

V = A.pos - B.posのような感じで。

B.pos = B.pos + V

とすると、当たり前だけど、ティーポットは原点に移動する。

ベクトルの計算(位置)だけだとシンプルだが、回転、スケールも考慮する場合はどうだろうか?そのような際に3D変換マトリックスを使った演算がとても強力だと思う。

原点からBの変換行列は、B.transform の値そのもの


Bから原点の変換行列(逆行列)はinverseを使って求める事が出来るようだ。


そして、自分の変換行列に、自分の逆行列を掛け算してあげると・・・
ティーポットが原点に移動し、回転、スケールもリセットされる。



inverseは反転。つまり「-」と考える事が出来るので

原点の変換行列 = 元の行列 - 元の行列

と考えると覚えやすいか。


相対的な変換行列の取得

AからBへのベクトル = B.pos - A.pos
AからBへの変換行列 = B.transform * (inverse A.transform)


BからAへのベクトル = A.pos - B.pos
BからAへの変換行列 = A.transform * (inverse B.transform)

---
TM = A.transform * (inverse B.transform)
B.transform = TM * B.transform

とすると、Bの変換がAの変換と同じになるのが確認出来るかと思う。

【実用例】動いているオブジェクト(Teapot001)に追従(リンク)するカメラ(Camera001)をオブジェクトを止めて同じように見えるようにする

新しく動いていないTeapot002と動いていないCamera002を作成して
動いていないカメラ、Camera002のTransformにScriptコントローラーを適用して以下のように記述。

トラッキングした情報をカメラに適用するか、オブジェクトに適用するかなども同じ仕組みだと思われる。オブジェクトを止めた状態でカメラの動きをつけて動いているカメラにその変換情報を渡してあげるとか。


<解説>
1.$Camera001.transform * (inverse $Teapot001.transform)とし、Teapot001からCamera001への相対的な変換マトリックスを取得

この変換をワールド座標で表すと以下の感じだと思われるので、ワールド原点を基準にしたい場合はこれだけで終わり(なはず・・・)。

2. 1で得た変換マトリックスをTeapot002の所に持ってくる。(Teapot002の子にする)
この計算をした場合、Teapot002の変換が考慮されているので、Teapot002を動かしたり、アニメーションを付けたとしても、Cameraとの相対関係は維持されたままになる(はず)。


カメラのトランスフォームをワールドX軸で対象にする
$Camera002.transform = $Camera001.transform * (scaleMatrix [-1,1,1])
とするとシンプルなのだが、この場合スケールの値がマイナスとなり、カメラやライトの場合は反転してしまって、上手くいかなかったので、xformMat関数を使い変換を変換した。オブジェクトなどでも、レンダリング時などエラーが起きそうですし。変換を変換。変換を・・・。

tiraokaさんのブログでカメラの変換トランスフォームを使って、素材の座標を変換する方法を説明してますが、考え方は同じになりますか。勉強になります。

ColorMatrix

0 件のコメント:

コメントを投稿