UDIMはとても便利で良い技術なんですが、たまにバラバラにしたくなるんですよね。
プレビューも最近のviewportとかだとできるんですけども、
やっぱりバラバラにしたくなるんですよね。
設計
バラバラと言ってもどうするかですが、最終的には1テクスチャー1マテリアルにして、
UVエリア毎にそのマテリアルをアサインするイメージですね。
なので、やらねばならない事は
- UDIMで使用されているテクスチャーを取得
- テクスチャー1枚ごとにマテリアルを作成、fileノードを接続しテクスチャを登録
- 該当するUVエリアのUVからfaceIDを取得し、マテリアルをアサイン
こんなですかね。
マスクとかテクスチャーが複数刺さってる場合もありますが、その辺は一旦見なかったことにして・・・
テスト用のデータをこんな感じで準備しました。
実装
- 該当するUVエリアのUVからfaceIDを取得
この部分を実装してみます。
まぁ例によって力技ですが、
- face総当たりでUVを取得
- UVポイントが指定した範囲に収まってるか否かを判定
- 判定がTrueならfaceのIDを格納
こんな流れでやってみます。
import maya.api.OpenMaya as om
def findUVRangeFace(target,uvSet,UVRange):
faceIds = []
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)
for index in face_ids:
it.setIndex(index)
try:
uvs = it.getUVs(uvSet)
except:
continue
insideRange = True
for uPoint in uvs[0]:
if uPoint < UVRange[0] or uPoint > UVRange[1]:
insideRange = False
for vPoint in uvs[1]:
if vPoint < UVRange[2] or vPoint > UVRange[3]:
insideRange = False
if insideRange:
faceIds.append(index)
result = []
for faceId in faceIds:
result.append(target+".f["+str(faceId)+"]")
return result
テストしてみますと、
cmds.select(findUVRangeFace("pPlane1","map1",[0.0,1.0,0.0,1.0]))
cmds.select(findUVRangeFace("pPlane1","map1",[1.0,2.0,1.0,2.0]))
うまいこと取れてそうですね。
これをベースに他も組んでみます。
import maya.api.OpenMaya as om
import maya.cmds as cmds
import os
import pathlib
import re
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[ID[0]] = fileDirPath + node.name
return UDIMIDict
def findUVRangeFace(target,uvSet,UVRange):
faceIds = []
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)
for index in face_ids:
it.setIndex(index)
try:
uvs = it.getUVs(uvSet)
except:
continue
insideRange = True
for uPoint in uvs[0]:
if uPoint < UVRange[0] or uPoint > UVRange[1]:
insideRange = False
for vPoint in uvs[1]:
if vPoint < UVRange[2] or vPoint > UVRange[3]:
insideRange = False
if insideRange:
faceIds.append(index)
result = []
for faceId in faceIds:
result.append(target+".f["+str(faceId)+"]")
return result
def separateUDIMMT(MTPrefix,fileNode,uvSet):
UDIMFileDict = getUDIMFileIDs(fileNode)
history = cmds.listHistory(fileNode,f=True) or []
SGs = cmds.ls(history, type = "shadingEngine") or []
if len(SGs) == 0:
return
##generate UDIM MT
UDIM_MTDict = {}
for UDIMID in list(UDIMFileDict.keys()):
filePath = UDIMFileDict[UDIMID]
shader = cmds.shadingNode('lambert', name = MTPrefix + "_" +UDIMID, asShader=True)
fileNode = cmds.shadingNode('file', asTexture=True)
shadingEngine = cmds.sets(renderable=1, noSurfaceShader=1, empty=1, name=shader + "SG")
cmds.connectAttr(fileNode + ".outColor", shader + ".color")
cmds.connectAttr(shader + ".outColor", shadingEngine + ".surfaceShader")
cmds.setAttr(fileNode + ".fileTextureName",filePath,type = "string")
UDIM_MTDict[UDIMID] = shadingEngine
for SG in SGs:
targets = cmds.sets(SG,q=True) or []
for UDIMID in list(UDIM_MTDict.keys()):
UVRange = [
float(UDIMID[-1]) - 1.0,
float(UDIMID[-1]),
float(UDIMID[-2]),
float(UDIMID[-2])+ 1.0,
]
for target in targets:
faces = findUVRangeFace(target,uvSet,UVRange)
if len(faces) != 0:
cmds.sets(faces,e =True,forceElement = UDIM_MTDict[UDIMID])
さてこれを実行してみると
separateUDIMMT("hoge","file1","map1")
マテリアルが生成され、faceにアサインされました!