MaxScriptで各行列を抽出してみた

わりと試行錯誤してしまったので、自分へのメモも兼ねて投稿します。


MaxScriptで、オブジェクトの回転行列だけ取り出したいという事がありました。
しかし、オブジェクトが持っているプロパティは、各成分は、値として所持しており、『拡大』『回転』『平行移動』が合成されたトランスフォームだけだったりします。→ [**参考**](https://help.autodesk.com/view/3DSMAX/2018/JPN/?guid=__files_GUID_D1D7EB56_A370_4B07_99B4_BC779FB87CAF_htm
)
その為、各成分だけの行列を取り出したい場合は、以下の2通りになると考えられます。

1. オブジェクトの所持ているプロパティから作成する
2. 合成トランスフォームから、抜き出す

:::note info
1の方法は上手く行かなかった為、2の方法で取り出しました。
:::


検証環境
3DS Max 2022 ※ ツールのアップデートが遅れている為、2022で検証しています



# 作成したソースコード

関数化して、すぐに使えるようなコードになっています。
引き数は、取り出したいオブジェクトのtransformプロパティとなっています。
『拡大行列』『平行移動行列』に関しては、単位行列に必要な成分を入れて、なるべくプレーンな状態の行列を作成しています。
『回転行列』は、拡大成分が合成されている為、一度、拡大行列を作成し、その逆行列を使って抜き出しています。
行列の計算に関しては、 [**こちら**](https://qiita.com/niusounds/items/cb821062acfd353d088d)の記事を参考にさせていただきました。


```actionscript
-- execute使用時は、グローバルでないと駄目
oPyramid001 = execute( "$Pyramid001" )
oPyramid002 = execute( "$Pyramid002" )
-- Pyramid002の位置をリセット
oPyramid002.transform = matrix3 1


-- 平行移動行列を抜き出す
fn GetLocationMatrix _mtx =
(
	-- 行成分抜き出し
	local pRow1 = [1, 0, 0]
	local pRow2 = [0, 1, 0]
	local pRow3 = [0, 0, 1]			
	local pRow4 = _mtx.row4

	-- 平行移動行列作成
	local outputMtx = matrix3 pRow1 pRow2 pRow3 pRow4 

	outputMtx
)

-- 拡大行列を抜き出す
fn GetScaleMatrix _mtx =
(
	-- 行成分抜き出し
	local inRow1 = _mtx.row1
	local inRow2 = _mtx.row2
	local inRow3 = _mtx.row3

	-- 拡大・縮小行列作成
	local mtxX =  sqrt ( inRow1.x * inRow1.x + inRow2.x * inRow2.x + inRow3.x * inRow3.x )
	local mtxY =  sqrt ( inRow1.y * inRow1.y + inRow2.y * inRow2.y + inRow3.y * inRow3.y )
	local mtxZ =  sqrt ( inRow1.z * inRow1.z + inRow2.z * inRow2.z + inRow3.z * inRow3.z )
	local sRow1 = [mtxX, 0, 0]
	local sRow2 = [0, mtxY, 0]
	local sRow3 = [0, 0, mtxY]			
	local sRow4 = [0, 0, 0]			
	local outputMtx = matrix3 sRow1 sRow2 sRow3 sRow4
	
	outputMtx
)

-- 回転行列を抜き出す
fn GetRotationMatrix _mtx =
(	
	local scaleMtx = GetScaleMatrix _mtx
	local ideScaleMtx = inverse scaleMtx

	-- 行成分抜き出し
	local inRow1 = _mtx.row1
	local inRow2 = _mtx.row2
	local inRow3 = _mtx.row3
	local inRow4 = scaleMtx.row4
	
	-- 回転・拡大行列抜き出し・作成
	local srMtx = matrix3 inRow1 inRow2 inRow3 inRow4

	-- 逆行列で行列を求める
	local outputMtx = srMtx * ideScaleMtx
	
	outputMtx	
)


--
-- 動作テスト
--
(
	-- 拡大行列を取得
	local scaleMtx     = GetScaleMatrix oPyramid001.transform
	-- 回転行列を取得
	local rotationMtx = GetRotationMatrix oPyramid001.transform
	-- 平行移動行列を取得
    local locationMtx = GetLocationMatrix oPyramid001.transform
	-- 拡大 x 回転 x 平行移動
    local gousei =  scaleMtx * rotationMtx * locationMtx

	-- 別のオブジェクトに反映させて行列のチェック
    oPyramid002.transform = gousei --結果を反映

	print scaleMtx
	print rotationMtx
	print locationMtx
	print gousei
)
```


# 結果

実行結果です。

Pyramid001が表示されている状態です。
Pyramid001は、拡大・回転・平行移動されているオブジェクトです。

![Pyramid001が表示されている.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/2561c172-21e6-e0b7-9c77-423dc8f67f82.png)

Pyramid002が表示されている状態です。
Pyramid002は、初期状態で何の変換も加えていないオブジェクトです。
スクリプトでPyramid001と同じ変換を与えています。

![Pyramid002が表示されている.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/f21daad4-bd06-b157-f5fe-ef8bd78eb3ec.png)

二つのオブジェクトを表示した結果です。
重なっている事が確認できると思います。

![二つのオブジェクト重なっている.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/e57fdde2-57a0-1fce-30b9-38e4c221370e.png)


# おまけ


もう一つの[**面白いアプローチ**](https://ngroku.com/?p=3621)としては、拡大・回転・平行移動のプロパティから、行列を作るという方法があった為、試しましたが、こちらは、私の方では上手く行きませんでした。
合成した行列をPyramid002に反映したところ、若干ずれがありました。
これは、Maxのバージョンによる挙動の変更などの違いかも知れませんが、各プロパティから行列を作れる事がわかり勉強になりました。


# 参考

* https://qiita.com/niusounds/items/cb821062acfd353d088d
* https://ngroku.com/?p=3621