【Maya/Python】 SIのように内部エッジを回転させてみる(Turn Internal Edges)

今月は珍しく更新が多いですw

 

SIでは内部エッジ(Internal Edges)を回転させるコマンドがデフォルトで付いていました。

Mayaでも割ってあるエッジに対しては回転させるコマンドがありますが、

自分は四角ポリとかを三角に割らずに内部エッジを回転させたいのですよ。

 

なぜかというと例えばその四角ポリを半分に割ったりしたい場合、

三角に割って中にエッジがある場合そのエッジにも頂点を追加して割らないといけないのが微妙に手間なんですよ

 

そこでどうにかできないかなぁと試行錯誤して、それっぽいスクリプトはできました!

ただ、ほんとにまだそれっぽいだけで、100%納得のいく動作にはなっていません・・・(;´∀`)

なのでver0.9というかbeta版的なやつです。

現状のスクリプトがどんなことしているかというと、選択されているポリゴン(複数可)のから

・頂点番号

・頂点座標

・UV番号

・UV座標

を取得してリストに入れて、リスト内の頂点座標の順番を入れ替える。

選択していたポリゴンを一旦削除して、並び替えた頂点番号のリストをもとに新しくポリゴンを生成。

そのポリゴンのUVを事前に取得していた元のUVの位置に戻す。

 

みたいなことをやっています。

これで、捻れていないような状態のポリゴンであればUVも破壊せずに内部エッジを回転させられます。

例えば、プリミティブのボックスやシリンダー、スフィアのポリゴンは大丈夫です。

 

ただ、「捻れていない」と書いたように頂点の位置によって内部エッジが変わるとシルエットが大きく変わるものに関してはこのスクリプトは効きませんでした・・・。

(※5頂点以上のポリゴンだと内部エッジが回ったり回ってくれなかったり・・・ これも課題です。)

 

僕の予想では、Mayaさんは自分でエッジを入れて三角化しない限りは

頂点の位置などから内部的に内部エッジを決めつけているんじゃないかと思っています。

 

三角化orエッジ追加して、そのエッジをスピンさせると各頂点法線の角度も変わるので

もしかしたらそれを無理矢理変更すれば・・・?とか考えましたが、

そもそも分割した場合はエッジが入っている頂点の法線情報が2つ分(XYZ*2)持っています。

分割していない場合は分かれていないので1つ分しか持てないのでこの方法もダメそうです(たぶん…)

 

そんな中途半端スクリプトですが、公開しておきますので

もしこの解決方法やもっといい処理の方法をご存知の方がいらっしゃいましたらお教えください。

 

こちらからもDLできます。

 


# -*- coding: utf-8 -*-
'''
Created on 2016/02/22

@author: redglasses67

ver 0.9
'''
import maya.cmds as mc
import re

def kTurnInternalEdges():

    sel = mc.ls( sl=True )

    if not sel:
        print 'Nothing is selected'

    else:
        faceNum = mc.polyEvaluate( faceComponent=True )

        if faceNum == 0:
            print ("Please select polyface!!")

        else:
            selMask = mc.filterExpand( sel , selectionMask=34 )
            meshName = selMask[ 0 ][ 0 : selMask[ 0 ].rfind(".") ]

            #選択したポリゴンを切り離し
            mc.polyChipOff(selMask , duplicate=False )
            #ポリゴンから頂点情報を照会
            polyInfos = mc.polyInfo( selMask, faceToVertex=True )

            #選択しているポリゴンの頂点とUVを取得する
            oldVtx , oldVtxPos , oldUV , oldUvPos = getVtxAndUV( polyInfos , meshName )

            #内部エッジの向きを変えるために頂点とUVのリストを並び替える
            for i in range( len( oldVtxPos ) ):
                replaceVtx = oldVtxPos[ i ][ 0 ]
                oldVtxPos[ i ].pop( 0 )
                oldVtxPos[ i ].append( replaceVtx )
                oldVtxPos[ i ].reverse()

                replaceUV = oldUvPos[ i ][ 0 ]
                oldUvPos[ i ].pop( 0 )
                oldUvPos[ i ].append( replaceUV )
                oldUvPos[ i ].reverse()

                replaceNormal = oldVtxNormal[ i ][ 0 ]
                oldVtxNormal[ i ].pop( 0 )
                oldVtxNormal[ i ].append( replaceNormal )
                oldVtxNormal[ i ].reverse()


            #選択していたポリゴンを削除
            mc.polyDelFacet( selMask )

            #ポリゴン追加前のポリゴンのリストを取得
            mc.select( meshName + ".f[*]" )
            oldPolyList = mc.filterExpand( mc.ls(sl=True) , selectionMask=34 )

            #選択していた頂点座標をpolyAppendVertexに渡してポリゴンを生成
            for vtxs in oldVtxPos:
                mc.polyAppendVertex( append = vtxs )

            #ポリゴン追加後のポリゴンのリストを取得するために
            #選択していたオブジェクトのポリゴンを全選択
            mc.select( meshName + ".f[*]" )
            newPolyList = mc.filterExpand( mc.ls(sl=True) , selectionMask=34 )

            #追加後のリストと追加前のリストから差分を求めて生成されたポリゴンを取得
            setList = set( newPolyList ) - set( oldPolyList )
            newList = list( setList )

            #上記の情報から追加したポリゴンを選択する
            mc.select( newList )
            selNewPoly = mc.ls(sl=True)
            newPolyInfos = mc.polyInfo(selNewPoly, faceToVertex=True)

            #追加したポリゴンの頂点とUVを取得する
            newVtx , newVtxPos , newUV , newUvPos = getVtxAndUV( newPolyInfos , meshName )

            #UVの位置を戻すために元の頂点座標と現在の頂点座標が同じになるインデックスを求め、
            #そのUVリストのインデックスが示すUV座標に現在のUVを移動させていく
            for x in range( len( newVtxPos ) ):
                for y in range( len( newVtxPos[ x ] ) ):
                    for z in range( len( newVtxPos[ x ][ y ] ) ):
                        try:
                            indx = oldVtxPos[ x ].index( newVtxPos[ x ][ y ] )
                            mc.polyEditUV( newUV[ x ][ y ] , relative=False , uValue = oldUvPos[ x ][ indx ][ 0 ] , vValue = oldUvPos[ x ][ indx ][ 1 ] )
                        except:
                            pass

            #生成したポリゴンが裏返っているので反転
            mc.polyNormal( selNewPoly ) #normalMode=0

            #一度ポリゴンを全選択して生成されたポリゴンの頂点を周囲とマージさせる
            mc.select( meshName + ".f[*]" )
            mc.polyMergeVertex( distance=0.001 )
            mc.select( newList )


def getVtxAndUV( polyInfo , name ):
    polyCount = len( polyInfo )

    #選択されてるポリゴン数分の空リストを作っておく
    vtxList = [ [] for i in range( polyCount ) ]
    vtxPosList = [ [] for i in range( polyCount ) ]
    uvList = [ [] for i in range( polyCount ) ]
    uvPosList = [ [] for i in range( polyCount )]

    polyNum = 0

    for info in polyInfo:

        #polyInfosから取得する情報から"FACE"を消すために数字のみ取り出す
        matchInfo = re.findall( r"[0-9]+" , info )

        #最初の数字はポリゴンの番号なのでリストから削除
        matchInfo.pop(0)

        vtxCount = len( matchInfo )

        for a in range( vtxCount ):
            vtxList[ polyNum ].append( [ None ] )
            uvPosList[ polyNum ].append( [ None ])
            uvList[ polyNum ].append( [ None ] )

            #頂点番号から各頂点のローカル座標を取得していく
            vtx = name + ".vtx[" + matchInfo[ a ] + "]"
            vtxList[ polyNum ][ a ] = vtx
            matchInfo[ a ] = mc.pointPosition(vtx, local=True)

            for b in range(len( matchInfo[ a ])):
                matchInfo[ a ][ b ] = round( matchInfo[ a ][ b ] , 3)
                if abs( matchInfo[ a ][ b ]) < 0.001:
                    matchInfo[ a ][ b ] = 0.0

            #各頂点からUVをリストに入れていく
            uvList[ polyNum ][ a ] = mc.polyListComponentConversion( vtx, toUV=True )

        #頂点の座標値をリストに入れていく
        vtxPosList[ polyNum ] = matchInfo

        for c in range( len( uvList[ polyNum ] )):
            #各UVの座標をリストに入れていく
            uvPosList[ polyNum ][ c ] = mc.polyEditUV( uvList[ polyNum ][ c ], q=True )

        polyNum += 1

    return vtxList , vtxPosList , uvList , uvPosList

kTurnInternalEdges()