UDIMのファイルがあるかチェックしたい

UDIM話が続きます。

https://qiita.com/9boz/private/0b743d6836f95f099f48

https://qiita.com/9boz/private/82629c0c015ec2653e95

UDIMは連番になってはいるのですが、
途中が抜けていても特に自己主張がないので
レンダリングしたら　あれなんか変だ？　ってことがありました。

なので、UVが配置されているエリアにUDIMファイルが存在するか否かを調べてみます。

追加
--

とりあえず先述の2つの記事の内容を流用すればなんかできそうですが、

- UDIMで使われているUVエリア

この部分は新規に起こす必要がありそうです。

UV座標を総当たりで確認し、小数点以下を切り捨ててUDIMのIDに変換していきます。
ただ、UDIMの範囲が大きくなるとどうなるのかちょっとわからないので、ひとまず狭い範囲だけ対応ということで。

```python
def checkUVRange(target,uvSet):
    mesh_dagPath = om.MGlobal.getSelectionListByName(target).getDagPath(0)
    shape_Fn = om.MFnMesh(mesh_dagPath)
    face_ids = range(0,shape_Fn.numPolygons)
    it = om.MItMeshPolygon(mesh_dagPath)

    DUIMAreas = []

    for index in face_ids:
        it.setIndex(index)

        try:
            uvs = it.getUVs(uvSet)
        except:
            continue
            
        for uPoint,vPoint in zip(uvs[0],uvs[1]):
            uArea = math.floor(uPoint)+1
            vArea = math.floor(vPoint)            
            UDIMArea = str(vArea) + str(uArea)
            
            if UDIMArea not in DUIMAreas:
                DUIMAreas.append(UDIMArea)
    return DUIMAreas
```

テストシーンで確認すると、とれてそうですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/9838dc6d-ede2-70c9-c086-7eb2a40520a9.png)

```python
checkUVRange("pPlane1","map1")
# Result: ['12', '03', '11', '02', '13', '01'] # 
```


実装
--


```python
import maya.api.OpenMaya as om
import maya.cmds as cmds
import os
import pathlib
import re
import math

def getUDIMFileIDs(fileNode):
    filePath = cmds.getAttr(fileNode + ".computedFileTextureNamePattern")

    fileDirPath = os.path.dirname(filePath) + "/"
    fileName = os.path.basename(filePath)    
    fileNameSample = fileName.replace("<UDIM>","([0-9|\-]{4})")    
    pathNode = pathlib.Path(fileDirPath).iterdir()    
    UDIMIDict = {}
    
    for node in pathNode:
        if node.is_dir():
            continue
                    
        elif node.is_file():
            ID = re.findall(fileNameSample,node.name) or None
            
            if ID == None:
                continue
            
            if ID[0] not in list(UDIMIDict.keys()):
                UDIMIDict[int(ID[0])] = fileDirPath + node.name

    return UDIMIDict

def checkUVRange(target,uvSet):
    mesh_dagPath = om.MGlobal.getSelectionListByName(target).getDagPath(0)
    shape_Fn = om.MFnMesh(mesh_dagPath)
    face_ids = range(0,shape_Fn.numPolygons)
    it = om.MItMeshPolygon(mesh_dagPath)

    DUIMAreas = []

    for index in face_ids:
        it.setIndex(index)

        try:
            uvs = it.getUVs(uvSet)
        except:
            continue
            
        for uPoint,vPoint in zip(uvs[0],uvs[1]):
            uArea = math.floor(uPoint)+1
            vArea = math.floor(vPoint)
            
            UDIMArea = str(vArea) + str(uArea)
            
            if UDIMArea not in DUIMAreas:
                DUIMAreas.append(UDIMArea)
                
    DUIMAreas.sort()
    return DUIMAreas


def checkUDIMFiles(fileNode,uvSet):
    UDIMFileDict = getUDIMFileIDs(fileNode)
    history = cmds.listHistory(fileNode,f=True) or []
    SGs = cmds.ls(history, type = "shadingEngine") or []        
    allUDIMIDs = []
    for SG in SGs:
        targets = cmds.sets(SG,q=True) or []
        for target in targets:
            UDIMIDs = checkUVRange(target,uvSet)
            
            for UDIMID in UDIMIDs:
                udim = 1000 + int(UDIMID)
                if udim not in allUDIMIDs:
                    allUDIMIDs.append(udim)         

    missingID = list(set(allUDIMIDs) - set(UDIMFileDict.keys()))
    
    return missingID

```

試しに　1003だけ逃がして実行してみますと

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/392d81d1-9ba3-354f-5ba2-e52085f2013b.png)

```python
checkUDIMFiles("file1","map1")
# Result: [1003] # 
```

検知されました。

改修案
--

UDIMファイルの連番名の生成がちょっと今回雑なので、
もっと大量のUDIM連番になった場合は対応できないかもしれません。

その辺直さねばかなぁ