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?

More than 1 year has passed since last update.

maya でハードエッジを転送したい

Posted at

よし、ハードエッジの設定が終わったぞ。
あー・・・右側もか・・・・・ってなった場合に、

パッと思いつくやり方は

  • 左のオブジェクトを複製して、反転させてリネーム
  • 右のオブジェクトも左と同じになるように設定

あれ?ハードエッジ情報って転送できないんだっけ?

標準機能でできないか?

とりあえずできそうなのは、transfer Attributes かなぁ

こんな設定で
image.png

こんなオブジェクトを
image.png

あ、出来た
image.png
お、もうこれは終わりですかね?

もう1パターン、こんなオブジェクトを
image.png

ん?間違ったかな?
image.png

ん?ん?
何をどうやっても転送できねぇ
他に出きそうな機能も見当たらないので、一旦切り替え。

※標準機能で転送する方法ご存じの方いらっしゃったら是非教えてください。

ハードエッジ情報

ハードエッジ情報はどこに格納されているのかなぁー
先述のテストで転送出来たってことはvertexNormalと関係してるとは思うのですが、それは完全ではない。
つまりハードエッジ情報は別途どこかに格納されとるんではなかろうか。

と仮定。

エッジは、所有する 2 つのフェース間の角度が、スムージング角度より鋭角(大きい)の場合にハードになります。
所有する 2 つのファセット間の角度が、スムージング角度より鈍角(小さい)場合はソフトになります。

そっかーフェースかー
フェースノーマルはvtxノーマルで定義されるしなぁ・・・
失敗したケースは平面だったから???

OpenMaya.MFnMesh.isEdgeSmooth()
あ、こんなのもありますね。

ということはエッジ毎に ハードorソフト が確認できるようですね。

エッジからエッジへ

ならば、こうだ。

  • 転送元オブジェクトのハードなエッジIDを取得
  • 転送先オブジェクトのハードエッジを全部ソフト化
  • 転送先オブジェクトでエッジIDを元にハードを設定

こんな流れで。

  • ハードなエッジIDの取得
    まぁとりあえず総当たりで
import maya.api.OpenMaya as om
import maya.cmds as cmds

def getDagNode(target):    
    try:
        sellist = om.MGlobal.getSelectionListByName(target)
        return sellist.getDagPath(0)
    except:
        return None

def getShapeFn(dagPath):
    FnShape = None
    if dagPath.hasFn(om.MFn.kMesh):
        FnShape = om.MFnMesh(dagPath)        
    elif dagPath.hasFn(om.MFn.kNurbsSurface):
        FnShape = om.MFnNurbsSurface(dagPath)
    elif dagPath.hasFn(om.MFn.kNurbsCurve):
        FnShape = om.MFnNurbsCurve(dagPath)
    return FnShape

def getHardEdges(target):
    dagPath = getDagNode(target)
    FnShape = getShapeFn(dagPath)
    edgeNum = FnShape.numEdges

    hardIDs = []
    for edgeID in range(0,edgeNum):
        if FnShape.isEdgeSmooth(edgeID)==False:            
            hardIDs.append(edgeID)

    return hardIDs
  • ハードエッジを全部ソフト化
    まぁ全部ソフトエッジ化すればいいんですわよね

とおもったけど、transformノード指定してpolySoftEdgeで行けますね。

cmds.polySoftEdge(target, ch = False,angle =180)
  • エッジIDを元にハードを設定
import maya.cmds as cmds

def setHardEdge(target,edgeIDs):    
    targetEdges = []
    for edgeID in edgeIDs:
        targetEdges.append(target + ".e["+str(edgeID)+"]")

    cmds.polySoftEdge(targetEdges, ch = False,angle =0)

これらを組み合わせて

import maya.api.OpenMaya as om
import maya.cmds as cmds
def getDagNode(target):    
    try:
        sellist = om.MGlobal.getSelectionListByName(target)
        return sellist.getDagPath(0)
    except:
        return None

def getShapeFn(dagPath):
    FnShape = None
    if dagPath.hasFn(om.MFn.kMesh):
        FnShape = om.MFnMesh(dagPath)        
    elif dagPath.hasFn(om.MFn.kNurbsSurface):
        FnShape = om.MFnNurbsSurface(dagPath)
    elif dagPath.hasFn(om.MFn.kNurbsCurve):
        FnShape = om.MFnNurbsCurve(dagPath)
    return FnShape

def getHardEdges(target):
    dagPath = getDagNode(target)
    FnShape = getShapeFn(dagPath)
    edgeNum = FnShape.numEdges

    hardIDs = []
    for edgeID in range(0,edgeNum):
        if FnShape.isEdgeSmooth(edgeID)==False:            
            hardIDs.append(edgeID)

    return hardIDs

def setHardEdge(target,edgeIDs):    
    targetEdges = []
    for edgeID in edgeIDs:
        targetEdges.append(target + ".e["+str(edgeID)+"]")

    cmds.polySoftEdge(targetEdges, ch = False,angle =0)

def transferHardEdge(source, target):
    edgeIDs = getHardEdges(source)
    cmds.polySoftEdge(target, ch = False,angle =180)
    setHardEdge(target,edgeIDs)

先ほどの失敗ケースでテスト
image.png

問題なく転送出来た様子。

そういえば

終わりじゃない。
1つここで思い出したことが

見た目が完全に一緒でも faceのIDが異なる場合がある
vtxIDが完全に一致しててもfaceのIDが異なる場合がある

これedgeでもあり得るのかな?

image.png

はい あり得ました。
1本エッジを削除して、connectComponentでつなぎ直してみたところ
edgeIDはずれました。

エッジをvtxにして、vtxからエッジに

edge貼り直しても幸い vtxIDは変わらないので、
vtxIDのorderは一致しているというのを最低限の条件として再考。

  • 転送元オブジェクトのハードなedgeを取得
  • エッジを構成しているvtxIDを取得
  • 転送先オブジェクトでvtxIDで構成されるedgeIDを取得
  • 転送先オブジェクトのハードエッジを全部ソフト化
  • 転送先オブジェクトでedgeIDをハードを設定

こんなところでしょうか。

  • エッジを構成しているvtxIDを取得

こんな感じで

def getEdgeContainVtx(target,edgeIDs):    
    dagPath = getDagNode(target)
    FnShape = getShapeFn(dagPath)
    edgeVtxDict = {}
    
    for edgeID in edgeIDs:
        vtexIds = FnShape.getEdgeVertices(edgeID)        
        edgeVtxDict[edgeID] = vtexIds

    return edgeVtxDict

  • 転送先オブジェクトでvtxIDで構成されるedgeIDを取得

vtxに接続しているedgeは複数本あるので、
それらのうちで 指定したvtxすべてに接続されているedgeを探せばいいかしら?

def convertVtexToEdge(target,edgeVtxDict):
    dagPath = getDagNode(target)
    FnShape = getShapeFn(dagPath)        
    it = om.MItMeshVertex(dagPath)
    convertedDict = {}

    for key in list(edgeVtxDict.keys()):
        shareEdges = []

        for vtexID in edgeVtxDict[key]:    
            it.setIndex(vtexID)
            edges = it.getConnectedEdges()

            if len(shareEdges) == 0:
                shareEdges = edges
            else:    
                shareEdges = list(set(shareEdges) & set(edges))

        if len(shareEdges) == 0:
            continue

        for shareEdge in shareEdges:
            convertedDict[shareEdge] = edgeVtxDict[key]
              
    return convertedDict

まとめる

まとめるとこんな感じ

import maya.api.OpenMaya as om
import maya.cmds as cmds
def getDagNode(target):    
    try:
        sellist = om.MGlobal.getSelectionListByName(target)
        return sellist.getDagPath(0)
    except:
        return None

def getShapeFn(dagPath):
    FnShape = None
    if dagPath.hasFn(om.MFn.kMesh):
        FnShape = om.MFnMesh(dagPath)        
    elif dagPath.hasFn(om.MFn.kNurbsSurface):
        FnShape = om.MFnNurbsSurface(dagPath)
    elif dagPath.hasFn(om.MFn.kNurbsCurve):
        FnShape = om.MFnNurbsCurve(dagPath)
    return FnShape

def getHardEdges(target):
    dagPath = getDagNode(target)
    FnShape = getShapeFn(dagPath)
    edgeNum = FnShape.numEdges

    hardIDs = []
    for edgeID in range(0,edgeNum):
        if FnShape.isEdgeSmooth(edgeID)==False:            
            hardIDs.append(edgeID)

    return hardIDs

def setHardEdge(target,edgeIDs):    
    targetEdges = []
    for edgeID in edgeIDs:
        targetEdges.append(target + ".e["+str(edgeID)+"]")

    cmds.polySoftEdge(targetEdges, ch = False,angle =0)

def getEdgeContainVtx(target,edgeIDs):    
    dagPath = getDagNode(target)
    FnShape = getShapeFn(dagPath)
    edgeVtxDict = {}
    
    for edgeID in edgeIDs:
        vtexIds = FnShape.getEdgeVertices(edgeID)        
        edgeVtxDict[edgeID] = vtexIds

    return edgeVtxDict

def convertVtexToEdge(target,edgeVtxDict):
    dagPath = getDagNode(target)
    FnShape = getShapeFn(dagPath)        
    it = om.MItMeshVertex(dagPath)
    convertedDict = {}

    for key in list(edgeVtxDict.keys()):
        shareEdges = []

        for vtexID in edgeVtxDict[key]:    
            it.setIndex(vtexID)
            edges = it.getConnectedEdges()

            if len(shareEdges) == 0:
                shareEdges = edges
            else:    
                shareEdges = list(set(shareEdges) & set(edges))

        if len(shareEdges) == 0:
            continue

        for shareEdge in shareEdges:
            convertedDict[shareEdge] = edgeVtxDict[key]
              
    return convertedDict

def transferHardEdge(source, target):
    edgeIDs = getHardEdges(source)
    edgeVtxDict = getEdgeContainVtx(source,edgeIDs)
    
    cmds.polySoftEdge(target, ch = False,angle =180)
    convertedDict = convertVtexToEdge(target,edgeVtxDict)    
    setHardEdge(target,list(convertedDict.keys()))
    
sel = cmds.ls(sl =True)
transferHardEdge(sel[0], sel[1])

vtxIDは一致してるけど、edgeID順がズレてるコレでテスト
image.png

よし、うまく行きました
image.png

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?