ノードの種類に関係なく、現在のジオメトリ情報を取得する

投稿者: | 2018/12/09

MaxScriptを書いていると、現在のノードの種類に関係なく、ビューポート上でのジオメトリ情報を取得したくなるケースがあります。
今回はそういった場合のデータの取得方法について。

基本は.meshプロパティ

例えば、ノードのマップチャンネル数を取得したくなった場合、ノードが編集可能ポリゴンなら以下のような方法で取得できます。

polyop.getNumMaps $
-- または
polyop.getNumMaps $.baseObject

しかし、この方法で取得できるのは、編集可能ポリゴンの値だけです。
例えば、対象がメッシュだったりプリミティブだったり、あるいはモディファイヤが設定されていた場合はどうすればいいでしょうか。
もちろん、ノードタイプ毎に処理を分岐する事は出来ますが、対応できるタイプには限界があります。

そういった場合、ほとんどのケースでノードの.meshプロパティから情報を取得すると、問題が解決します。
下の例では、選択がどんなオブジェクトかに関わらず、ほとんどの場合でマップチャンネル数を取得できます。

meshop.getNumMaps $.mesh

ノードのmeshプロパティは、現在のビューポートにおける、ノードのTriMesh値を取得します。
TriMeshは、平たく言えば編集出来ないEditable_Meshです。Editableじゃないやつですね。

取得されたメッシュはシーン内に実態を持ちませんので、取得後にわざわざ削除する必要はありません。
また、内部にキャッシュを持っているのか、かなり高速に取得されます。
(少なくとも、snapshotを作るより遥かに高速です。)

ただし、.meshを取得できないケースもあるので注意が必要です。
例えばスプラインからは取得できません。

c = Circle()
c.mesh
-- > ランタイム エラー: このオブジェクトからメッシュを取得できません : Circle

スプラインはメッシュを持たないので当たり前ですが、「ビューポートを有効」にチェックを入れていて、メッシュを表示している場合でも取得出来ません。
その場合、ノードにポリゴンかメッシュ系のモディファイヤを追加しておけば、取得できるようになります。

c = Circle()
c.displayRenderMesh = true
addModifier c (Edit_Poly())

c.mesh
-- > TriMesh

スプラインはこれ以外にも何かと問題になります。
面倒くさいですね。

ちなみにプリミティブ系はそのままでも取得出来ます。

頂点数の取得

ノードの頂点数を取得したい場合、上記の.meshを使う方法の他に、ノードの組み込み関数numPointsも利用することができます。

t = teapot()
convertToPoly t

-- .meshを使う場合
meshop.getNumVerts t.mesh
-- > 530

-- 組み込み関数を使う場合
numPoints t
-- > 530

ティーポットを作成し、ポリゴンに変換後、値を取得しています。

ここで注意しなければならいのは、numPointsは「編集可能な頂点数」を取得するという点です。
ポリゴンに変換している点でピンと来た人も居るかもしれませんが、numPointsは「編集できない頂点」数は取得してくれません。
編集できない頂点というのは、例えばプリミティブの構成頂点等です。

試しにポリゴンに変換せずに取得した場合、以下のようになります。

t = teapot()
numPoints t
-- > 0

また、編集可能スプラインでは、そのスプラインのノット数を取得します。

c = circle()
convertTo c SplineShape

numPoints c
-- > 12

スプラインにおける編集可能な頂点=ノットという訳です。
これはこれで便利なのですが、場合によっては意図しない挙動になる事もあるので、やはり注意が必要です。

頂点座標の取得

上記の.meshを取得する方法を使えば、ノードのジオメトリ頂点を取得する事が出来ます。

theMesh = $.mesh
for i = 1 to getNumVerts theMesh collect
    getVert theMesh i

-- > #([2.46742,-20.7206,79.1154], [2.15734,-22.5598,81.3849], ...

ただし、取得される頂点座標はローカル系で取得されます。
ワールド座標を取得したい場合、予めノードのobjectTransformを取得しておき、座標に行列変換を掛ける必要があります。
objectTransformプロパティは、そのノードのビューポート内での現在のジオメトリ変換を取得する事が出来ます。

theMesh = $.mesh
objMtx = $.objectTransform
for i = 1 to getNumVerts theMesh collect
    (getVert theMesh i) * objMtx

このobjectTransformを掛ける方法はかなり色々な事に応用出来るので、覚えておいて損は無いと思います。

上記の方法以外に、ノードの組み込み関数getPointPosを利用する方法もあります。
こちらは、頂点数取得のnumPointsと同じく、「編集可能な頂点」座標になりますので、状況に応じて使い分けてください。

in coordsys #world
(
    for i = 1 to numPoints $ collect
        getPointPos $ i
)

取得は現在、または指定した座標系コンテキストで行われます。

値の設定は?

残念ながら値の設定関数はありません。
.meshプロパティもTriMeshは編集不可データなので、set***系の関数が動作しません。
値の設定を行いたい場合は、今まで通りモディファイヤなりベースオブジェクトなりで個別の処理が必要です。

このあたり何とかなればいいんですけど・・・

誰か知っていたら教えてください。

コメントを残す

メールアドレスが公開されることはありません。