MaxScriptTip: 座標系の変換

7月 18, 2016
MaxScriptでは座標系の制御にin coordsysコンテキストが使えますが、場合によってはこのコンテキストが作用しないケースがあります。

例えば法線編集モディファイヤで扱う法線情報は、常にローカル座標としてやり取りされます。
また、各モディファイヤのギズモ関係も多くの場合in coordsysが効きません。
しかしそうなってくると困るのが、異なるオブジェクト/モディファイヤ間での座標のやり取りです。
そうういったケースでは、座標を自力で変換する必要があります。

ローカル→ワールド

特定のオブジェクトのローカル座標をワールド座標に変換するには、対象オブジェクトの行列を取得して、ローカル座標に行列変換をかけます。
local mtx = in coordsys #world obj.transform
local worldVerts = (for v in localVerts collect v * mtx)
座標(point3)への行列変換は、単に行列(matrix3)を掛けるだけです。


ワールド→ローカル

逆にワールド座標系をローカルに戻す場合は、対象オブジェクトの逆行列を取得します。
逆行列とは読んで字の如く、特定の行列と全く逆の変換をする行列です。
逆行列は、行列オブジェクトに対してinverse関数を使う事で取得出来ます。
local invMtx = in coordsys #world inverse obj.transform
local localVerts = (for v in worldVerts collect v * invMtx)
分かってしまえば簡単ですね。


ローカル→ローカル

最後に異なるローカル間での変換について。
上の2つの例では行列の取得を#worldコンテキストで行っていますが、ローカル間で直接変換する場合は変換先オブジェクトの座標コンテキストで取得します。
local mtx = in coordsys targetObj selfObj.transform
local targetVerts = (for v in selfVerts collect v * mtx)
もちろんワールド座標を経由して変換しても同じ座標を取得する事が出来ますが、変換回数が1回増えるのでどちらがいいかはケースバイケースですね。

(補足)法線変換の注意点

変換対象が座標の時はいいのですが、対象が法線のような方向ベクトルの時、注意点があります。
法線には移動オフセットの概念が無いので、行列に移動変換が入っていると正しい計算結果になりません。
そういう訳で、その場合は行列の移動変換をクリアしてやる必要があります。

それともう一つ、変換にスケールが入っていると変換後の法線が単位ベクトル(長さ1.0のベクトル)にならない事があります。 これについても変換後に正規化する事で対応する事ができます。
local mtx = in coordsys #world obj.transform
mtx.row4 = [0,0,0]
local newNormals = (for n in oldNormals collect normalize (n * mtx))

Related Articles