【MAYA】マテリアルのフェイスアサイン時に、マテリアル未定義面ができていないか確認する

![image.png](https://qiita-image-store.s3.amazonaws.com/0/8302/28c5b96d-560f-406b-93c2-8c3ee0c3e81d.png)
MAYAでは（何らかの事故で）マテリアルのアサインが取れてしまったポリゴンの表示はこのように蛍光グリーンのような色で表示されるわけですが、

![image.png](https://qiita-image-store.s3.amazonaws.com/0/8302/9109cf7f-e32c-af2b-7de7-e84256957b8b.png)
フェイスアサインで一部だけマテリアルがないような状態も作ることができます。これは、フェイスとSGのコネクションを切るだけではダメで、そのような場合は代わりにcompInstObjGroups（コンポーネントインスタンスオブジェクトグループ）で設定されているマテリアルが適用されます。なのでそのcompInstObjGroups側のSGとのコネクションも切ってやることでこのような状態を作り出す事ができます。

作れるからといって、偶然できてしまう事があるのかというとそうそうないのでは？ と思ってしまうのですが、知人曰くできたことがあるっぽいので、これを判定するプログラムを書いてみます。

##注意点
* そもそもコンポーネントインスタンスオブジェクトグループの存在意義について理解仕切れていないので大きな間違いをしている可能性があります。
* コードがかなり力技です。例によってもっとスマートに解決できる気がします。

##実際のコード
```python
def is_face_assigned_all(shape):
    """
    フェイスアサインの抜けがあって、マテリアル未定義面ができていないか確認する

    :param shape: チェックするシェイプ
    :type shape: pymel.nodetypes.Shape
    :rtype: bool
    """
    # compInstObjGroupsからコネクションがSGに伸びていればフェイスアサインに抜けがあってもマテリアルがない面が現れることはない
    indices = shape.compInstObjGroups.getArrayIndices()
    found = False
    for i in indices:
        group = shape.compInstObjGroups[i].compObjectGroups[0]
        cons = pm.listConnections(group, plugs=True)
        if len(cons) > 0 and cons[0].type() == 'shadingEngine':
            found = True
            break
    if found:
        return True
    # フェイス面ごとにフラグを持ってマテリアルアサイン抜けがある部分を探す
    instanceNumber = shape.instanceNumber()
    indices = shape.instObjGroups[instanceNumber].objectGroups.getArrayIndices()
    numFaces = shape.numFaces()
    assined_map = [False] * numFaces
    for i in indices:
        objectGrpCompList = shape.instObjGroups[instanceNumber].objectGroups[i].objectGrpCompList
        faces_list = objectGrpCompList.get()  # ex) ['f[0]','f[1:3]']
        # 返ってきたフェイス情報が文字列なので力技で面番号のリストに変換する。。。
        for faces in faces_list:
            faces = faces[2:-1]  # ex) '0' or '1:3'
            if ':' in faces:
                a_ = [int(x) for x in faces.split(':')]  # ex [1,3]
                a_ = xrange(a_[0], a_[1] + 1)  # ex [1,2,3]
            else:
                a_ = [int(faces)]  # ex [0]
            # マテリアル設定があった面情報としてTrueをセット
            for i in a_:
                assined_map[i] = True
    #一つもFalseがなかったら全ての面にマテリアルが定義されている
    return not (False in assined_map)
```
文字列をホゲってるあたりが力技です。

##動作検証
前回と同じ検証シーン（やっつけ感半端ない）を使います。

<img width="324" alt=" 2018-01-10 3.46.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/8302/3c37fd8b-30d6-4dd2-492f-4145c445fd73.png">
_下からpCube1,2,3,4,5,6_

```python

shape = pm.PyNode('pCube1|pCubeShape1')  # フェイスアサインのないインスタンスシェイプ
print(is_face_assigned_all(shape)) # -> False

shape = pm.PyNode('pCube2|pCubeShape1')  # フェイスアサインのあるインスタンスシェイプ
print(is_face_assigned_all(shape)) # -> True

shape = pm.PyNode('pCube3|pCubeShape3')  # インスタンスが存在しないフェイスアサインのないシェイプ
print(is_face_assigned_all(shape)) # -> False

shape = pm.PyNode('pCube4|pCubeShape4')  # インスタンスが存在しないフェイスアサインのあるシェイプ
print(is_face_assigned_all(shape)) # -> True

shape = pm.PyNode('pCube5|pCubeShape5')  # マテリアルが外れてしまったシェイプ
print(is_face_assigned_all(shape)) # -> False

shape = pm.PyNode('pCube6|pCubeShape6')  # 一部faceのマテリアルが外れてしまったシェイプ
print(is_face_assigned_all(shape)) # -> False
```

とりあえず、正しく動いているようです。