MAYAのインスタンスの振る舞いに続いて、(世の中で嫌われていそうな)マテリアルのフェイスアサインについてPymelを使ったプログラム視点で調査したのでメモを残してみます。
以下は、MAYA2018 + MacOS Sierraで動作確認しています。ソース中pm
となっているのはimport pymel.core as pm
という形でインポートされた PymelCoreオブジェクトです。ソース中、出力:
と書いてある部分は、結果表示を自分がわかりやすくコメントの形で書き写した部分で、実際のMAYA上の画面とは異なります。
フィイスアサイン前後の差異


メンバーワイヤーフレームカラー
SGそれぞれからShapeに逆向きに伸びるコネクションです。見やすくビューのノードの左右位置を入れ替えて詳しく見てみます。
メンバーワイヤフィレームカラーからオブジェクトグループのカラーという所へコネクションが伸びています。詳しい値をscriptで表示してみます。
sg1 = pm.PyNode('phong1SG')
print(sg1.memberWireframeColor.get())
# 出力:-1
print(sg1.memberWireframeColor.listConnections(plugs=True))
# 出力:[Attribute(u'pCubeShape1.instObjGroups[0].objectGroups[0].objectGrpColor')]
sg2 = pm.PyNode('phong2SG')
print(sg2.memberWireframeColor.get())
# 出力:-1
print(sg2.memberWireframeColor.listConnections(plugs=True))
# 出力:[Attribute(u'pCubeShape1.instObjGroups[0].objectGroups[1].objectGrpColor')]
sg1、 sg2共にほぼ同じ状態で、異なるのはobjectGroupsのインデックス番号だけです。このobjectGroupsの番号がズバリ、フェイスのグループ番号を示すようです。青いフェイス部分がグループ0で、黄色い部分がグループ1という事ですね。
pCubeShape1.instObjGroups[0].objectGroups[0]
は、つまり、pCubeShape1
のデフォルトインスタンスのフェイスグループ0という意味でしょう。
そして、memberWireframeColor
というのはどうも作業画面上のワイヤフレームのカラー表示設定のようで、ユーザーが自由にカスタマイズして使うことができるもののようです。値の-1というのはデフォルト値で設定なし、です。と、するとこのカラー番号を指定するUIがMAYAのSGのインスペクタ上に存在しそうなものですが見つかりません。。
見つからないのですが、重要そうなノード接続ではなさそうなので、深く考えずに先に進みます。
インスタンスオブジェクトグループのオブジェクトグループ

shape = pm.PyNode('pCubeShape1')
print(shape.instObjGroups[0].listConnections(plugs=True))
# 出力:[Attribute(u'phong1SG.dagSetMembers[0]')]
instObjGroups[0]
からphong1SG.dagSetMembers[0]
に接続が伸びています。

sg1 = pm.PyNode('phong1SG')
print(sg1.dagSetMembers[0].listConnections(plugs=True, source=True))
# 出力:[Attribute(u'pCubeShape1.instObjGroups[0].objectGroups[0]')]
sg2 = pm.PyNode('phong2SG')
print(sg2.dagSetMembers[0].listConnections(plugs=True, source=True))
# 出力:[Attribute(u'pCubeShape1.instObjGroups[0].objectGroups[1]')]
SGそれぞれ2つのdagSetMembers[0]
から逆方向にコネクションを出力させてみましたが、フェイスアサイン前のinstObjGroups[0]
ではなく、instObjGroups[0].objectGroups[0]
とinstObjGroups[0].objectGroups[1]
に接続先が変わりました。フェイスごとにSGに接続が伸びるようになったという事ですね。
さらに、objectGroup(=フェイスのグループ)について詳しく内容を表示してみます。
shape = pm.PyNode('pCubeShape1')
objectGroup = shape.instObjGroups[0].objectGroups[0]
attr_names = pm.listAttr(objectGroup)
for attr_name in attr_names:
print('{}'.format(attr_name))
# 以下出力:
# instObjGroups[0].objectGroups[0]
# instObjGroups[0].objectGroups[0].objectGrpCompList
# instObjGroups[0].objectGroups[0].objectGroupId
# instObjGroups[0].objectGroups[0].objectGrpColor
どのような属性があるのか羅列してみました。
objectGroups
そのものと、objectGrpCompList
、objectGroupId
、objectGrpColor
が存在するようです。
それぞれの型と値を表示してみます。
objectGroup = shape.instObjGroups[0].objectGroups[0]
attrs = (objectGroup, objectGroup.objectGrpCompList,
objectGroup.objectGroupId, objectGroup.objectGrpColor)
for a in attrs:
print('{}({}) : {}'.format(a, a.type(), a.get()))
# 以下出力:
# pCubeShape1.instObjGroups[0].objectGroups[0](TdataCompound) : [[u'f[1:5]'], 20, -1]
# pCubeShape1.instObjGroups[0].objectGroups[0].objectGrpCompList(componentList) : [u'f[1:5]']
# pCubeShape1.instObjGroups[0].objectGroups[0].objectGroupId(long) : 20
# pCubeShape1.instObjGroups[0].objectGroups[0].objectGrpColor(short) : -1
-
objectGroups[0]
はTdataCompound
という型で、この場合は他の情報をひとまとめにした型という事のようです。値の表示も他の3つのデータがそのままリストで並んでいます。 -
objectGrpCompList
はcomponentList
という型で、uf[1:5]
という文字列の内容から察するにフェイス番号1から5の集合という意味ではないでしょうか。 -
objectGroupId
はlong
の数値型でフェイスグループのID番号のようです。 -
objectGrpColor
はshort
の数値型で前述したように枠線表示などに利用される色番号のようです。
別フェイスグループの方も見てみます。
objectGroup = shape.instObjGroups[0].objectGroups[1]
attrs = (objectGroup, objectGroup.objectGrpCompList,
objectGroup.objectGroupId, objectGroup.objectGrpColor)
for a in attrs:
print('{}({}) : {}'.format(a, a.type(), a.get()))
# 以下出力:
# pCubeShape1.instObjGroups[0].objectGroups[1](TdataCompound) : [[u'f[0]'], 22, -1]
# pCubeShape1.instObjGroups[0].objectGroups[1].objectGrpCompList(componentList) : [u'f[0]']
# pCubeShape1.instObjGroups[0].objectGroups[1].objectGroupId(long) : 22
# pCubeShape1.instObjGroups[0].objectGroups[1].objectGrpColor(short) : -1
おおよそ予想通りの内容が表示されました。フェイス番号0が一つ設定されています。キューブの場合全フェース数は6個なので、辻褄が合います。
なお、このようなフェイスアサインにした場合、
objectGroups[0].objectGrpCompList
の値は、[u'f[0]', u'f[2:3]', u'f[5]']
と、なりました。飛び飛びのフェイス番号が登録されています。
ここまでは、問題なく理解できました。
コンポーネントのインスタンスオブジェクトグループ
マテリアルのフェイスアサインにすると変化するコネクションの最後の1つ、一番厄介そうな奴を見ていきます。




フェイスアサインがなかった場合のデフォルトのマテリアル設定を保持している、と考えれば良いでしょうか。よくわからないので、詳細の調査に進みます。
shape = pm.PyNode('pCubeShape1')
compInstObjGroups = shape.compInstObjGroups[0]
attr_names = pm.listAttr(compInstObjGroups)
for attr_name in attr_names:
print('{}'.format(attr_name))
# 以下出力:
# compInstObjGroups[0]
# compInstObjGroups[0].compObjectGroups
# compInstObjGroups[0].compObjectGroups.compObjectGrpCompList
# compInstObjGroups[0].compObjectGroups.compObjectGroupId
compObjectGroups = compInstObjGroups.compObjectGroups[0] # ここで[0]にしないとMAYAが落ちる
attrs = (compInstObjGroups,
compObjectGroups,
compObjectGroups.compObjectGrpCompList,
compObjectGroups.compObjectGroupId
)
for attr in attrs:
print('{}({}) {}'.format(attr, attr.type(), attr.get()))
# 以下出力:
# pCubeShape1.compInstObjGroups[0](TdataCompound) (0.0,)
# pCubeShape1.compInstObjGroups[0].compObjectGroups[0](TdataCompound) [None, 2]
# pCubeShape1.compInstObjGroups[0].compObjectGroups[0].compObjectGrpCompList(None) None
# pCubeShape1.compInstObjGroups[0].compObjectGroups[0].compObjectGroupId(long) 2
ここで、compInstObjGroups[0]
とcompObjectGroups
はTdataCompound
型で、compObjectGrpCompList
にはNone
が、compObjectGroupId
には2
が設定されています。
さて、値がNoneとは。。?
ちなみにこの値はマテリアルのフェイスアサイン前にも存在はしていて、
# pCubeShape1.compInstObjGroups[0](TdataCompound) (0.0,)
# pCubeShape1.compInstObjGroups[0].compObjectGroups[0](TdataCompound) [None, 0]
# pCubeShape1.compInstObjGroups[0].compObjectGroups[0].compObjectGrpCompList(None) None
# pCubeShape1.compInstObjGroups[0].compObjectGroups[0].compObjectGroupId(long) 0
のような状態になりました。
さらによくわかりませんが、#2に続きます。#2ではシェイプのインスタンスを作成して異なるフェイスアサインをしてみます。