0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MayaAdvent Calendar 2024

Day 11

UDIMをバラバラにしたい

Last updated at Posted at 2024-12-10

UDIMはとても便利で良い技術なんですが、たまにバラバラにしたくなるんですよね。

プレビューも最近のviewportとかだとできるんですけども、
やっぱりバラバラにしたくなるんですよね。

設計

バラバラと言ってもどうするかですが、最終的には1テクスチャー1マテリアルにして、
UVエリア毎にそのマテリアルをアサインするイメージですね。

なので、やらねばならない事は

  • UDIMで使用されているテクスチャーを取得
  • テクスチャー1枚ごとにマテリアルを作成、fileノードを接続しテクスチャを登録
  • 該当するUVエリアのUVからfaceIDを取得し、マテリアルをアサイン

こんなですかね。

マスクとかテクスチャーが複数刺さってる場合もありますが、その辺は一旦見なかったことにして・・・

テスト用のデータをこんな感じで準備しました。

image.png

実装

  • 該当する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]))

image.png

cmds.select(findUVRangeFace("pPlane1","map1",[1.0,2.0,1.0,2.0]))

image.png

うまいこと取れてそうですね。

これをベースに他も組んでみます。

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")

image.png

マテリアルが生成され、faceにアサインされました!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?