my funeral week

少しでも日々の生活に変化を。

MayaScripts_FollowerGenerator:選択ノードに追従するノードを生成

ニッチなことかもしれませんが、とあるTransformノードに対して位置や回転を追従するTransformノードが欲しいことってありませんか?

私はあるんすよ。

FollowerGenerator

Transformノードの位置と回転に追従するTransformノードを生成する。
そういうスクリプトです。

コード

# encoding:utf-8

import pymel.core as pm

VERSION = "1.1"

print ("-*- import {0}.{1} -*-".format(__name__,VERSION))

SUFIX = "_Follower"
VISIBLE = False
LOCKATTR = True
LOCKATTR_TARGET = ["translate", "rotate", "scale", "visibility"]
STRIP_NAMESPACE = True
LOCATOR_NODE = False
WINDOWNAME = "FollowerGen"
WINDOWSIZE = [160,78]

def __createFollowerNode (name):
    """Follower用のTransformノードを生成"""
    # type:(str) -> pm.nodetypes.Transform
    
    follower = None

    if LOCATOR_NODE:
        follower = pm.spaceLocator(n = name)
        follower.getShape().setAttr("v", VISIBLE)
    else:
        follower = pm.createNode("transform", n = name)

    return follower
    
    
def __createFollowerName (target_node):
    """Followerノード用の名前を生成"""
    # type:(pm.nodetypes.Transform) -> str
    
    return target_node.name(stripNamespace = STRIP_NAMESPACE) + SUFIX
    
    
def __generateFollower (target_node, const_flags):
    # type:(pm.nodetypes.Transform, list[bool]) -> pm.nodetypes.Transform
    
    follower = __createFollowerNode(__createFollowerName(target_node))
    
    if const_flags[0] : pm.pointConstraint(target_node, follower)
    if const_flags[1] : pm.orientConstraint(target_node, follower)
    
    for a in LOCKATTR_TARGET : follower.setAttr(a, lock = LOCKATTR)
        
    return follower
    
    
def __generateFollowers (target_nodes, const_flags = [True, True]):
    """Targetノードに対してFollowerを生成"""
    # type:(list[pm.nodetypes.Transform], list[bool]) -> list[pm.nodetypes.Transform]
    
    if not target_nodes : return None
    
    followers = list()
    
    for n in target_nodes:
        
        if not isinstance(n, pm.nodetypes.Transform) : continue
        
        followers.append(__generateFollower(n, const_flags))
            
    return followers
    
    
def __deleteExistUI (*arg):
    # type:(tuple) -> None
    
    if pm.window(WINDOWNAME, q = True, ex = True):
        pm.deleteUI(WINDOWNAME)
    
    
def __buildUI ():
    # type:() -> None
    
    __deleteExistUI()
    
    with pm.window(WINDOWNAME, mnb = False, mxb = False, s = False) as w:
        w.setWidthHeight(WINDOWSIZE)
        
        with pm.columnLayout(adj = True, rs = 2, co = ["both", 5]):
            
            pm.separator(st = "none", h = 1)
            
            pos_flag = pm.checkBox(l = "Position", v = True)
            rot_flag = pm.checkBox(l = "Rotation", v = True)
            
            cmd = lambda *arg:__generateFollowers(pm.selected(), [pos_flag.getValue(), rot_flag.getValue()])
            
            with pm.rowLayout(nc = 2):
                button_width = (WINDOWSIZE[0] * 0.5) - 6
                pm.button(l = "Generate", w = button_width, c = cmd)
                pm.button(l = "Close", w = button_width, c = __deleteExistUI)
            
def main ():
    
    if pm.getModifiers() == 5:
        __buildUI()
        return
    __generateFollowers(pm.selected())


インストール

上記コードを「FollowerGenerator.py」という名前のファイルに保存して、下記の場所においてください。

C:\Users\ユーザー名\Documents\maya\scripts


実行するには下記のコード。

import FollowerGenerator
FollowerGenerator.main()


使い方

追従したいノードを選択した状態で実行すると、下図のように「Transformノード」が生成されます。

選択したノードに対して位置と回転のコンストレイントが接続されていますので追従して動きます。


また、「Shift+Ctrl」を押しながら実行すると下図のUIが立ち上がります。

追従するTransformAttributeを位置と回転のいずれか、またはその両方をチェックボックスから選択できます。
「Generateボタン」を押すと選択中のTransformノードに対して、チェックした内容で追従するノードを生成します。


オプション

コード中の定数を変更することで、ちょっとしたオプションが利用可能です。

SUFIX = "_Follower" # 生成するノード名のサフィックス
VISIBLE = False # LOCATOR_NODEがTrueになっている場合、その可視性をこの値に設定します。
LOCKATTR = True # 生成したノードに不要なキーフレームを打てないように、下記のAttrをロックします。
LOCKATTR_TARGET = ["translate", "rotate", "scale", "visibility"]
STRIP_NAMESPACE = True # 生成するノード名に選択ノードのネームスペースを含めるか
LOCATOR_NODE = False # 生成するノードをLocatorにする

以上。