3dsMaxはオブジェクト名がシーン内で一意であることを保証していません。
その為、シーン内でオブジェクト名が重複する可能性が常にあり、名前によってオブジェクトを特定出来ないケースが度々発生します。スクリプト内でノードを保持出来るケースなら問題無いのですが、外部ツールと連携する時や.NETを使用する時などに問題になります。
そういう時には、オブジェクトを一意に特定出来るユニークIDを取得する必要があります。そこで今回は、MaxScriptでのオブジェクトIDの取得について、2種類の方法を紹介します。
inode.handleを使う方法
inode.handleは、全てのノードが持っているプロパティです。
例えばBoxやSphere、あるいはBoneやHelperなど、シーンに直接表示されるオブジェクトは、全てこの方法でIDを取得する事ができます。このIDは、シーン内で常にユニークである事を保証しており、シーンを保存して再起動した場合でも、IDが一巡するまでは必ず同一のノードを指します。
-- ノードからハンドルを取得
id = $box001.handle
-- ハンドルからノードを取得
theBox = maxOps.getNodeByHandle id
注意点として、ノードの種類によってはinodeとは別に固有のhandleプロパティを持っている事があります。その場合、明示的にinodeインタフェースを指定してやる必要があります。
-- これはIDではなくTeapotのhandleプロパティ。(取手のON/OFF)
$teapot001.handle
--> true
-- こうする事で確実にIDを取得
$teapot001.inode.handle
--> 1655
AnimHandleを使う方法
ノード以外のオブジェクト、例えばマテリアル、モディファイヤ、コントローラ等では、AnimHandleという仕組みを使う必要があります。AnimHandleは、文字通りAnimatableオブジェクトのハンドルを取得出来る仕組みで、シーン内のほぼ全てのオブジェクトIDを取得する事が出来ます。
-- box001のマテリアルからハンドルを取得
id = GetHandleByAnim $box001.material
-- ハンドルからマテリアルを取得
theMtl = GetAnimByHandle id
注意点として、このIDは同一のプロセス内でしか一意になりません。つまり、シーンをファイルに保存してMaxを再起動すると、そのIDは無効になってしまいます。
反面、同一プロセス内であれば、たとえ.NET APIであっても一意性は保証されます。
以下はMaxScriptマテリアルを、.NET APIマテリアルとして開き直すサンプルです。
-- AnimHandleを取得
mtlId = GetHandleByAnim $.material
-- DotNet APIでマテリアルを取得しなおす
iGlobal = (dotnetClass "Autodesk.Max.GlobalInterface").Instance
mtlIdPtr = dotNetObject "System.UIntPtr" mtlId
theMtl = iGlobal.Animatable.GetAnimByHandle mtlIdPtr