<< TOP

GTMF2015 ネタ
Maya;Pythonで表の作成と書き込み/読み込みツール を作ろう!!
Constraint Table

Maya; Let's Make a Table with Read/Write CSV Tool with Python
(Used Maya 2014, 2015 2016)
    プロローグ; Prologue
 GTMF2015 ネタ  Constraint Table
Maya で scriptTable というコマンドを使うと 表を作ることが出来ます。
この表の内容を CSV という Excel でも読み書き出来る カンマ(、)で
区切られたファイルに 書き込んだり、読み込んだりする仕組みを Python で実現します。
この機能の活用として コンストレイントのテーブルツールを作成します。

このツールは Rig 作成などでも便利で、あらかじめ決められたノード名に
決められたコンストレイントを一発で設定してくれます。
  (ほとんど同じような構造体のキャラRigを何体も作るような時等々)
 尚、GTMF2015での発表時よりも既に更新があり、Version2からの公開です。

 Version2
スケール コンストレイントに対応しました。

 なお、このサイトで掲載している事例の決まり事ですが、
使用に関しては自己責任でよろしくお願い申し上げます。
(Maya2014、2015、2016 で動作確認しています)

Please use it as your own risk.

Windows7 Professional 64Bit、Intel Core i7-3930K (3.20GHz,6コア/12スレッド)
メモリ16GB、NVIDIA GeForce GTX560 Ti 2GB (メモリ2GB)







 表の作成
     最初は、表を作成する Mayaのコマンド 、scriptTable から見てみましょう。

    おおまかなコマンドの説明は上記 ドキュメント が示しているので
    まずは、以下のようなスクリプトからスタートしてみます。

    import maya.cmds as cmds
    
    def edit_cell(row, column, value):
        return 1
    
    def add_row(*args):
        last_row_num = cmds.scriptTable('table', query=True, rows=True)
        cmds.scriptTable('table', edit=True,insertRow=last_row_num)
    
    def delete_row(*args):
        last_row_num = cmds.scriptTable('table', query=True, rows=True)
        cmds.scriptTable('table', edit=True,deleteRow=last_row_num - 1)
    
    window = cmds.window(widthHeight=(620, 300))
    
    form = cmds.formLayout()
    table =  cmds.scriptTable('table',rows=3, columns=7,columnWidth=([1,135],[2,145],[3,70],[4,45],[5,40],[6,40],[7,40]),
            label=[(1,"SourceNodeName"), (2,"DestinationNodeName"), (3,"Constrain"), (4,"Offset"), (5,"X"), (6,"Y"), (7,"Z")],
            cellChangedCmd=edit_cell)
    
    addButton = cmds.button(label="Add Row",command=add_row)
    deleteButton = cmds.button(label="Delete Row",command=delete_row)
    
    cmds.formLayout(form, edit=True, 
        attachForm=[(table, 'top', 0), (table, 'left', 0), (table, 'right', 0), 
        (addButton, 'left', 0), (addButton, 'bottom', 0), 
        (deleteButton, 'bottom', 0), (deleteButton, 'right', 0)],
        attachControl=(table, 'bottom', 0, addButton), 
        attachNone=[(addButton, 'top'),(deleteButton, 'top')], 
        attachPosition=[(addButton, 'right', 0, 50), (deleteButton, 'left', 0, 50)]
        )
    
    cmds.showWindow( window )


    ドキュメントのPython例で

    def edit_cell(row, column, value):
        return 1

     という記述がありますが、これ必ず必要です。
    これは、 cmds.scriptTable(rows=4, columns=2, label=[(1,"Column 1"), (2,"Column 2")], cellChangedCmd=edit_cell)
    とオフションの最後に edit_cell があり、”セルに変化が起こったら編集する” と設定しています。
     この記述が無いと、あれ?セルに値を記入しても受け付けない、という状態になります。

     window 内の表示は formLayout で作成しています。
    表を table として、
    また、2つの 行追加 と 削除ボタン を addButton  deleteButton として formLayout を使って並べます。

    window = cmds.window(widthHeight=(620, 300))
    form = cmds.formLayout()
    table = cmds.scriptTable('table',rows=3, columns=7,columnWidth=([1,135],[2,145],[3,70],[4,45],[5,40],[6,40],[7,40]),
            label=[(1,"SourceNodeName"), (2,"DestinationNodeName"), (3,"Constrain"), (4,"Offset"), (5,"X"), (6,"Y"), (7,"Z")],
            cellChangedCmd=edit_cell)
    
    addButton = cmds.button(label="Add Row",command=add_row)
    deleteButton = cmds.button(label="Delete Row",command=delete_row)


    こうすることによって、window サイズの変更に応じて 大きさが変化する2つのボタンをウィンドウ下部に配置します。
    行をドンドン追加していくと、表示しているウィンドウのサイズ以上に表が増えた場合は、右側にスライダーを出現して表の追加を続行します。
    ただ、気が付くのは、行の追加 削除 最後の行に対して 動作することです。

    そこで、こんな風に追加します。

    import maya.cmds as cmds
    
    def edit_cell(row, column, value):
        return 1
    
    def add_row(*args):
        last_row_num = cmds.scriptTable('table', query=True, rows=True)
        cmds.scriptTable('table', edit=True,insertRow=last_row_num)
    
    def delete_row(*args):
        last_row_num = cmds.scriptTable('table', query=True, rows=True)
        cmds.scriptTable('table', edit=True,deleteRow=last_row_num - 1)
    
    def insert_add_row(*args):
        try:
            selected_row = cmds.scriptTable('table', query=True, selectedRows=True)[0]
            if selected_row == None:
                print 'Select Row to Insert'
            else:
                cmds.scriptTable('table', edit=True,insertRow=selected_row)
        except:
            print 'Select Row to Insert'
    
    def delete_sel_row(*args):
        try:
            selected_row = cmds.scriptTable('table', query=True, selectedRows=True)[0]
            if selected_row == None:
                print 'Select Row to Delete'
            else:
                cmds.scriptTable('table', edit=True,deleteRow=selected_row)
        except:
            print 'Select Row to Delete'
    
    window = cmds.window(widthHeight=(620, 300))
    form = cmds.formLayout()
    table = cmds.scriptTable('table',rows=3, columns=7,columnWidth=([1,135],[2,145],[3,70],[4,45],[5,40],[6,40],[7,40]),
            label=[(1,"SourceNodeName"), (2,"DestinationNodeName"), (3,"Constrain"), (4,"Offset"), (5,"X"), (6,"Y"), (7,"Z")],
            cellChangedCmd=edit_cell)
    
    addButton = cmds.button(label="Add Row",command=add_row)
    deleteButton = cmds.button(label="Delete Row",command=delete_row)
    insertAddRowButton = cmds.button(label="Insert to Selected Row",command=insert_add_row)
    deleteSelRowButton = cmds.button(label="Delete Selected Row",command=delete_sel_row)
    
    cmds.formLayout(form, edit=True, 
        attachForm=[(table, 'top', 0), (table, 'left', 0), (table, 'right', 0), 
            (addButton, 'left', 0), (addButton, 'bottom', 0), 
            (deleteButton, 'bottom', 0), (deleteButton, 'right', 0),
            (insertAddRowButton, 'bottom', 0), (insertAddRowButton, 'right', 0),
            (deleteSelRowButton, 'bottom', 0), (deleteSelRowButton, 'right', 0)
            ],
        attachControl=(table, 'bottom', 0, addButton), 
        attachPosition=[(addButton, 'right', 0, 25),
            (deleteButton, 'left', 0, 25),(deleteButton, 'right', 0, 50),
            (insertAddRowButton, 'left', 0,50),(insertAddRowButton, 'right', 0, 75),
            (deleteSelRowButton, 'left', 0,75)], 
        attachNone=[(addButton, 'top'),(deleteButton, 'top'),(insertAddRowButton, 'top'),(deleteSelRowButton, 'top')]
        )
    
    cmds.showWindow( window )


     すると、左端のボタンを使って選択状態にした行部分に 新規の行を挿入したり 削除したり が行えるようになります。
    内容としては 選択行番号を cmds.scriptTable('table', query=True, selectedRows=True)[0] で求め、
    その番号行に対して 以下を実行しています。
    行の挿入 cmds.scriptTable('table', edit=True,insertRow=selected_row)
    行の削除 cmds.scriptTable('table', edit=True,deleteRow=selected_row)



 表への書き込み、取り出し
     コマンドの説明順的には、まずは値の取得からいった方が簡単です。
    では、出来たこの表に、今は適当な値を手で書き込んで、それを取り出したいと思います。



     次のスクリプトを実行します。

    print cmds.scriptTable('table', query=True, rows=True)
    
    4

     4 という数値が返って来ます。縦に 4行あって、1行目は ヘッダーとして文字が入っています。

    print cmds.scriptTable('table', query=True, columns=True)
    
    8

     8 という数値が返って来ます。横に 8列あって、1列目は 行選択ボタンになっています。
    つまり、上記例の ”20” となっている 縦2行目の横3列目 の値を取得するには、
    縦横の 0 から始まる数値で指定するので (1,2) となり、

    print cmds.scriptTable('table', cellIndex=(1,2), query=True, cellValue=True)[0]
    
    20

    となります。
     全体のデータを得るには、行数分、列の値を順に得るループを作成すればOKです。
    ヘッダー部分は None で返って来るところだけは気をつけて・・・、

    all_rows = cmds.scriptTable('table', query=True, rows=True)
    for o_r in range(all_rows):
        all_colums = cmds.scriptTable('table', query=True, columns=True)
        data_list = []
        for o_c in range( all_colums):
            cell_list = cmds.scriptTable('table', cellIndex=(o_r,o_c), query=True, cellValue=True)
            if type(cell_list) == 'list':
                cell_text = "".join(cell_list)
            elif cell_list == None:
                cell_text = cell_list
            else:
                cell_text = cell_list[0]
    
            data_list.append(cell_text)
        print data_list
    
    #結果
    [None, None, None, None, None, None, None, None]
    [None, u'1', u'20', u'30', u'1', u'10', u'20', u'30']
    [None, u'2', u'', u'', u'', u'', u'', u'']
    [None, u'3', u'', u'', u'', u'', u'', u'']
    


     さて、値の記入は query=True, を edit にして cellValue= に値を入れてば良い と気が付きます。

    cmds.scriptTable('table', cellIndex=(2,2), edit=True, cellValue=1000)


     次に考えるのは、ワークフロー的にどのような操作で順に値を入れると良いか、となります。
    ここでは、コンストレイントの表を作る予定なので、2列目・3列目はオブジェクトの名前、4列目はコンストレイントの種類の名前、オフセットの有無の0と1、座標値となります。
    きっと、1つ設定は、1つの組み合せとして、1行毎に横に書いて行って、表を埋めると考えます。
    表のどの部分に書き始めるかも自由なはずですから、選択された行に順々に書き込む と便利かなと想像します。

     ウィンドーにボタンを配置し、選択されている行の 決まった列に 選択しているオブジェクトの名前を記入する です。

    import maya.cmds as cmds
    
    def edit_cell(row, column, value):
        return 1
    
    def add_row(*args):
        last_row_num = cmds.scriptTable('table', query=True, rows=True)
        cmds.scriptTable('table', edit=True,insertRow=last_row_num)
    
    def delete_row(*args):
        last_row_num = cmds.scriptTable('table', query=True, rows=True)
        cmds.scriptTable('table', edit=True,deleteRow=last_row_num - 1)
    
    def insert_add_row(*args):
        try:
            selected_row = cmds.scriptTable('table', query=True, selectedRows=True)[0]
            if selected_row == None:
                print 'Select Row to Insert'
            else:
                cmds.scriptTable('table', edit=True,insertRow=selected_row)
        except:
            print 'Select Row to Insert'
    
    def delete_sel_row(*args):
        try:
            selected_row = cmds.scriptTable('table', query=True, selectedRows=True)[0]
            if selected_row == None:
                print 'Select Row to Delete'
            else:
                cmds.scriptTable('table', edit=True,deleteRow=selected_row)
        except:
            print 'Select Row to Delete'
    
    def set_sel1(*args):
        if not cmds.ls( selection=True ):
            print 'Select Object to List'
        else:
            selected_obj = cmds.ls( sl=True )[0]
            selected_row = cmds.scriptTable('table', query=True, selectedRows=True)
            if selected_row == None:
                print 'Select Row to List'
            else:
                selected_row = cmds.scriptTable('table', query=True, selectedRows=True)[0]
                cmds.scriptTable('table', edit=True, selectedCells=[selected_row,1])
                cmds.scriptTable('table', cellIndex=(selected_row,1), edit=True, cellValue=selected_obj)
                cmds.scriptTable('table', edit=True, selectedRows=selected_row)
    
    def set_sel2(*args):
        if not cmds.ls( selection=True ):
            print 'Select Object to List'
        else:
            selected_obj = cmds.ls( sl=True )[0]
            selected_row = cmds.scriptTable('table', query=True, selectedRows=True)
            if selected_row == None:
                print 'Select Row to List'
            else:
                selected_row = cmds.scriptTable('table', query=True, selectedRows=True)[0]
                cmds.scriptTable('table', edit=True, selectedCells=[selected_row,2])
                cmds.scriptTable('table', cellIndex=(selected_row,2), edit=True, cellValue=selected_obj)
                cmds.scriptTable('table', edit=True, selectedRows=selected_row)
    
    window = cmds.window(widthHeight=(620, 300))
    form = cmds.formLayout(numberOfDivisions=100)
    
    table1 = cmds.scriptTable('table',rows=3, columns=7,columnWidth=([1,135],[2,145],[3,70],[4,45],[5,40],[6,40],[7,40]),
        label=[(1,"SourceNodeName"), (2,"DestinationNodeName"), (3,"Constrain"), (4,"Offset"), (5,"X"), (6,"Y"), (7,"Z")],
        cellChangedCmd=edit_cell)
    
    addButton = cmds.button(label="Add Row",command=add_row)
    deleteButton = cmds.button(label="Delete Row",command=delete_row)
    insertAddRowButton = cmds.button(label="Insert to Selected Row",command=insert_add_row)
    deleteSelRowButton = cmds.button(label="Delete Selected Row",command=delete_sel_row)
    
    column = cmds.columnLayout()
    
    cmds.separator(height=10)
    cmds.text(label='Select Row to Input',width=420,bgc=[0.2,0.2,0.2],align='center' )
    cmds.rowLayout(numberOfColumns=2)
    cmds.button('set_bot1',label='Select SourceNodeName',width=210,bgc=[0.6,0.5,0.5],command=set_sel1)
    cmds.button('set_bot2',label='Select DestinationNodeName',width=210,bgc=[0.5,0.5,0.6],command=set_sel2)
    cmds.setParent('..')
    
    
    cmds.formLayout(form, edit=True,
        attachForm=[
            (table1, 'left', 5), (table1, 'top', 0), (table1, 'right', 5), (table1, 'bottom', 10),
            (column, 'top', 5), (column, 'left', 5),
    
            (addButton, 'left', 0), (addButton, 'bottom', 0), 
            (deleteButton, 'bottom', 0), (deleteButton, 'right', 0),
            (insertAddRowButton, 'bottom', 0), (insertAddRowButton, 'right', 0),
            (deleteSelRowButton, 'bottom', 0), (deleteSelRowButton, 'right', 0)
            ],
        attachControl=[(table1, 'top', 10,column ),(table1, 'bottom', 0, addButton)],
        attachPosition=[(column, 'right', 0, 100),
            (addButton, 'right', 0, 25),(deleteButton, 'left', 0, 25),(deleteButton, 'right', 0, 50),
            (insertAddRowButton, 'left', 0,50),(insertAddRowButton, 'right', 0, 75),(deleteSelRowButton, 'left', 0,75)],
        attachNone=[(addButton, 'top'),(deleteButton, 'top'),(insertAddRowButton, 'top'),(deleteSelRowButton, 'top')])
    
    cmds.showWindow( window )


    記入すべき行を選択していないと、行を選択してくれ と表示されます。
    あとは、これに従って記入用のボタンを増やしただけです。



 CSVファイルの読み込み/書き込み
     CSV (Comma Separated Values、カンマ区切り値列) ファイルは、単に ”、”(カンマ)で区切られたテキストファイルですが、
    Excelでは 表 として開ける便利なファイル形式です。
    また、Maya Pythonからも扱い易く、import csv と冒頭に書くだけで利用できるライブラリー対応です。


サンプルファイル >>  constraint_table_00.csv
     このサンプルファイルを Mayaのユーザーディレクトリー以下に置いたとして、以下を実行します。

    import csv
    
    o_file = open('C:/Users/ritaro/Documents/maya/2016/ja_JP/prefs/scripts/constraint_table_00.csv', 'r')
    reader = csv.reader(o_file)
    header = next(reader)
    
    for row in reader:
        print row[0] + ',' + row[1] + ',' + row[2] + ',' + row[3] + ',' + row[4] + ',' + row[5] + ',' + row[6]
    o_file.close()
    
    #結果
    pSphere1,pCube1,Point,1,,,
    pCone1,locator1,Orient,1,,,
    pCylinder1,pTorus1,Scale,0,2,2,2
    

    このように、openclose に挟んで reader で内容を上から行毎に文字どうり 読む ことが出来ます。

     では 次のステップとして、今は出来ている前章の表に 上の値を一旦手で入力しておいて、
    その内容を CSVファイルに書き込む ということをしてみます。
    まずは、表に constraint_table_00.csv の値を記入します。(第1行はヘッダーの為、2行目からになります)


     そして、以下のスクリプトで Mayaユーザーディレクトリーに constraint_table_01.csv として保存してみます。

    import maya.cmds as cmds
    import csv
    
    o_file = 'C:/Users/ritaro/Documents/maya/2016/ja_JP/prefs/scripts/constraint_table_01.csv'
    
    if not (cmds.file(o_file,query=True, exists=True)):
        tmp_csv_file = open(o_file, 'w' ,os.O_CREAT)
    else:
        tmp_csv_file = open(o_file, 'w')
    writer = csv.writer(tmp_csv_file, lineterminator='\n')
    
    all_rows = cmds.scriptTable('table', query=True, rows=True)
    for o_r in range(all_rows):
            
        all_colums = cmds.scriptTable('table', query=True, columns=True)
        data_list = []
        for o_c in range( all_colums - 1):
            if o_r == 0:
                data_list = ["SourceNodeName", "DestinationNodeName", "Constrain","MaintainOffset"]
            else:
                cell_list = cmds.scriptTable('table', cellIndex=(o_r,o_c + 1), query=True, cellValue=True)
                if o_c == 0:
                    if type(cell_list) == list:
                        cell_text = "".join(cell_list)
                        print cell_text
                    elif cell_list == None:
                        cell_text = u''
                    else:
                        cell_text = cell_list
                    data_list.append(cell_text)
                elif o_c == 1:
                    if type(cell_list) == list:
                        cell_text = "".join(cell_list)
                        print cell_text
                    elif cell_list == None:
                        cell_text = u''
                    else:
                        cell_text = cell_list
                    data_list.append(cell_text)
                else:
                    if type(cell_list) == list:
                        cell_text = "".join(cell_list)
                    elif cell_list == None:
                        cell_text = u''
                    else:
                        cell_text = cell_list
                    data_list.append(cell_text)
        writer.writerow(data_list)
    tmp_csv_file.close()

    Mayaのユーザーディレクトリー 以下に 新しく constraint_table_01.csv というファイルが作成されます。
    最初の open 記述部分が if 文で分岐になっている部分は面白く、
    その指定したファイル名の CSVファイルが無かった場合、つまり新規の場合は
    tmp_csv_file = open(o_file, 'w' ,os.O_CREAT) でファイルを作って開け と設定しています。

    中の記述も確認します。テキストとして開くと

    SourceNodeName,DestinationNodeName,Constrain,MaintainOffset
    pSphere1,pCube1,Point,1,,,
    pCone1,locator1,Orient,1,,,
    pCylinder1,pTorus1,Scale,0,2,2,2

    となっています。
    後は、この部分のスクリプトがボタンを押した時に動作すれば良い ということになります。

     残る動作対応としては、上記の逆、ですね。
    手入力して表を埋めるのではなく、新しく作成した constraint_table_01.csv ファイルから表に書き込みをします。
    もう一度 表を作るスクリプト を実行して、表の中身が全て空のものを用意します。
    そして、以下を実行します。

    import maya.cmds as cmds
    import csv
    
    o_file = open('C:/Users/ritaro/Documents/maya/2016/ja_JP/prefs/scripts/constraint_table_01.csv', 'r')
    reader = csv.reader(o_file)
    header = next(reader)
    
    row_no = 1
    for row in reader:
        if row_no > 3:
            cmds.scriptTable('table', edit=True,insertRow=row_no)
    
        cmds.scriptTable('table', cellIndex=(row_no,1), edit=True, cellValue=row[0])
        cmds.scriptTable('table', cellIndex=(row_no,2), edit=True, cellValue=row[1])
        cmds.scriptTable('table', cellIndex=(row_no,3), edit=True, cellValue=row[2])
        cmds.scriptTable('table', cellIndex=(row_no,4), edit=True, cellValue=row[3])
        cmds.scriptTable('table', cellIndex=(row_no,5), edit=True, cellValue=row[4])
        cmds.scriptTable('table', cellIndex=(row_no,6), edit=True, cellValue=row[5])
        cmds.scriptTable('table', cellIndex=(row_no,7), edit=True, cellValue=row[6])
        row_no = 1 + row_no
    
    o_file.close()

    結果は

    です。

     このように、表とCSVファイルを利用したツール作成が簡単に出来ることがわかります。



 表データに基づくコンストレイント
     表のデータからの実行ですが、これはもう表を順に上から読み取って
    データの種類によって異なる コンストレイント を設定している だけです。

    if o_conmodel == 'Point':
        o_conmodel_t = 'pointConstraint'
    elif o_conmodel == 'Orient':
        o_conmodel_t = 'orientConstraint'
    elif o_conmodel == 'Parent':
        o_conmodel_t = 'parentConstraint'
    elif o_conmodel == 'Scale':
        o_conmodel_t = 'scaleConstraint'

    追加の情報としては、キャラクターRigを作成する ことを前提に考えられているツールなので
    コンストレイントの元と先にそれぞれ別のネームスペースが付けられるようになっています。


    その部分の スクリプト です。(多少長いです。)

    def do_constraint(*args):
    
        try:
            o_namespace = cmds.textField('c_namespace',q=True,text=True)
            n_namespace = ""
            if o_namespace != "":
                n_namespace = o_namespace + ':'
    
            s_namespace = cmds.textField('d_namespace',q=True,text=True)
            m_namespace = ""
            if s_namespace != "":
                m_namespace = s_namespace + ':'
    
            last_row_num = cmds.scriptTable('table', query=True, rows=True)
            row_no = 1
            for row in range( last_row_num - 1):
                o_sname = cmds.scriptTable('table', cellIndex=(row_no,1), q=True, cellValue=True)[0]
                o_dname = cmds.scriptTable('table', cellIndex=(row_no,2), q=True, cellValue=True)[0]
                o_conmodel = cmds.scriptTable('table', cellIndex=(row_no,3), q=True, cellValue=True)[0]
                o_offmodel = cmds.scriptTable('table', cellIndex=(row_no,4), q=True, cellValue=True)[0]
    
                if o_sname == "" or o_dname == "" or o_conmodel == "" or o_offmodel == "":
                    cmds.confirmDialog( title='ERROR', message='No Node Name to Set !_! ')
                    break
                else:
                    if o_conmodel == 'Point':
                        o_conmodel_t = 'pointConstraint'
                    elif o_conmodel == 'Orient':
                        o_conmodel_t = 'orientConstraint'
                    elif o_conmodel == 'Parent':
                        o_conmodel_t = 'parentConstraint'
                    elif o_conmodel == 'Scale':
                        o_conmodel_t = 'scaleConstraint'
    
                    if o_offmodel == '0':
                        o_offmodel_t = 'False'
                        if o_conmodel == 'Parent':
                            if cmds.pointConstraint(m_namespace + o_dname,q=True) != None:
                                cmds.pointConstraint(n_namespace + o_sname,m_namespace + o_dname,edit=True,remove=True)
                            if cmds.orientConstraint(m_namespace + o_dname,q=True) != None:
                                cmds.orientConstraint(n_namespace + o_sname,m_namespace + o_dname,edit=True,remove=True)
    
                            do_const = "cmds." + o_conmodel_t + "('"+ n_namespace + o_sname +"','" + m_namespace + o_dname + "',maintainOffset=False)"
                            exec do_const
    
                        elif o_conmodel == 'Point':
                            if cmds.orientConstraint(m_namespace + o_dname,q=True) != None:
                                cmds.orientConstraint(n_namespace + o_sname,m_namespace + o_dname,edit=True,remove=True)
                            if cmds.parentConstraint(m_namespace + o_dname,q=True) != None:
                                cmds.parentConstraint(n_namespace + o_sname,m_namespace + o_dname,edit=True,remove=True)
    
                            o_off_x = cmds.scriptTable('table', cellIndex=(row_no,5), q=True, cellValue=True)[0]
                            if o_off_x == '':
                                o_off_x_t = '0.0000'
                            else:
                                o_off_x_t = str(o_off_x)
    
                            o_off_y = cmds.scriptTable('table', cellIndex=(row_no,6), q=True, cellValue=True)[0]
                            if o_off_y == '':
                                o_off_y_t = '0.0000'
                            else:
                                o_off_y_t = str(o_off_y)
    
                            o_off_z = cmds.scriptTable('table', cellIndex=(row_no,7), q=True, cellValue=True)[0]
                            if o_off_z == '':
                                o_off_z_t = '0.0000'
                            else:
                                o_off_z_t = str(o_off_z)
    
                            do_const = "cmds." + o_conmodel_t + "('" + n_namespace + o_sname +"','" + m_namespace + o_dname + "',maintainOffset=False,offset=[" + o_off_x_t + "," + o_off_y_t + "," +  o_off_z_t + "])"
                            exec do_const
    
                        elif o_conmodel == 'Orient':
                            if cmds.pointConstraint(m_namespace + o_dname,q=True) != None:
                                cmds.pointConstraint(n_namespace + o_sname,m_namespace + o_dname,edit=True,remove=True)
                            if cmds.parentConstraint(m_namespace + o_dname,q=True) != None:
                                cmds.parentConstraint(n_namespace + o_sname,m_namespace + o_dname,edit=True,remove=True)
    
                            o_off_x = cmds.scriptTable('table', cellIndex=(row_no,5), q=True, cellValue=True)[0]
                            if o_off_x == '':
                                o_off_x_t = '0.0000'
                            else:
                                o_off_x_t = str(o_off_x)
    
                            o_off_y = cmds.scriptTable('table', cellIndex=(row_no,6), q=True, cellValue=True)[0]
                            if o_off_y == '':
                                o_off_y_t = '0.0000'
                            else:
                                o_off_y_t = str(o_off_y)
    
                            o_off_z = cmds.scriptTable('table', cellIndex=(row_no,7), q=True, cellValue=True)[0]
                            if o_off_z == '':
                                o_off_z_t = '0.0000'
                            else:
                                o_off_z_t = str(o_off_z)
    
                            do_const = "cmds." + o_conmodel_t + "('" + n_namespace + o_sname +"','" + m_namespace + o_dname + "',maintainOffset=False,offset=[" + o_off_x_t + "," + o_off_y_t + "," +  o_off_z_t + "])"
                            exec do_const
    
                        elif o_conmodel == 'Scale':
                            if cmds.orientConstraint(m_namespace + o_dname,q=True) != None:
                                cmds.orientConstraint(n_namespace + o_sname,m_namespace + o_dname,edit=True,remove=True)
                            if cmds.parentConstraint(m_namespace + o_dname,q=True) != None:
                                cmds.parentConstraint(n_namespace + o_sname,m_namespace + o_dname,edit=True,remove=True)
    
                            o_off_x = cmds.scriptTable('table', cellIndex=(row_no,5), q=True, cellValue=True)[0]
                            if o_off_x == '':
                                o_off_x_t = '1.0000'
                            else:
                                o_off_x_t = str(o_off_x)
    
                            o_off_y = cmds.scriptTable('table', cellIndex=(row_no,6), q=True, cellValue=True)[0]
                            if o_off_y == '':
                                o_off_y_t = '1.0000'
                            else:
                                o_off_y_t = str(o_off_y)
    
                            o_off_z = cmds.scriptTable('table', cellIndex=(row_no,7), q=True, cellValue=True)[0]
                            if o_off_z == '':
                                o_off_z_t = '1.0000'
                            else:
                                o_off_z_t = str(o_off_z)
    
                            do_const = "cmds." + o_conmodel_t + "('" + n_namespace + o_sname +"','" + m_namespace + o_dname + "',maintainOffset=False,offset=[" + o_off_x_t + "," + o_off_y_t + "," +  o_off_z_t + "])"
                            exec do_const
    
                    else:
                        o_offmodel_t = 'True'
                        if o_conmodel == 'Parent':
                            if cmds.pointConstraint(m_namespace + o_dname,q=True) != None:
                                cmds.pointConstraint(n_namespace + o_sname,m_namespace + o_dname,edit=True,remove=True)
                            if cmds.orientConstraint(m_namespace + o_dname,q=True) != None:
                                cmds.orientConstraint(n_namespace + o_sname,m_namespace + o_dname,edit=True,remove=True)
                        elif o_conmodel == 'Point':
                            if cmds.orientConstraint(m_namespace + o_dname,q=True) != None:
                                cmds.orientConstraint(n_namespace + o_sname,m_namespace + o_dname,edit=True,remove=True)
                            if cmds.parentConstraint(m_namespace + o_dname,q=True) != None:
                                cmds.parentConstraint(n_namespace + o_sname,m_namespace + o_dname,edit=True,remove=True)
                        elif o_conmodel == 'Orient':
                            if cmds.pointConstraint(m_namespace + o_dname,q=True) != None:
                                cmds.pointConstraint(n_namespace + o_sname,m_namespace + o_dname,edit=True,remove=True)
                            if cmds.parentConstraint(m_namespace + o_dname,q=True) != None:
                                cmds.parentConstraint(n_namespace + o_sname,m_namespace + o_dname,edit=True,remove=True)
    
                        do_const = "cmds." + o_conmodel_t + "('" + n_namespace + o_sname +"','" + m_namespace + o_dname + "',maintainOffset=True)"
                        exec do_const
    
                row_no += 1
    
        except:
            cmds.confirmDialog( title='Name ERROR', message=' No Node Name to Constraint !! ')

    ここでは、 exec を使って、得たテキスト内容を実行しています。おもしろいですね。



 constraint_table
     ツールの説明です。
    まずは、表を記入する を左側のボタンを使って選択状態にします。



    コンストレイントのソースオブジェクト;[Select SourceNodeName]、影響を受けるオブジェクト;[Select DestinationNodeName]
    コンストレイントの種類、オフセットの有無、オフセット無しを選んだ場合のカスタム値(無記入は0,0,0になる)
    の順に、次々と行を埋めていきます。

     その表を保存したい場合は、[SAVE LIST to .CSV] ボタンで、一番上に書かれているファイルに記入されます。
    別名にしておけば、新規ファイルとして保存されます。

    ネームスペースを新たに追加したい場合は [SourceNamespace] / [DestinationNamespace] の下の空欄に記入します。

    [Do All Constraint] を押すと、表に書かれているものに従って 全てのコンストレイントが実行されます。



     利用例は、色々あるのですが、
    例えば、Rig作成時に、いつも決まった骨名同士に付ける各種コンストレイントは CSVとしてデータ化しておいて、
    いざMayaでRigを組む時は一発で設定を完了させたり、
    ネームスペースの有る無しでも同じコンストレイント設定を一発で実現したり、
    或いは、Maya上でアニメーションベイクをするとコンストレイントが外れてしまう場合、
    一発で元のコンストレイントを復活できるようにする・・・等々です。

    色々とカスタマイズすると、更に良いかも知れません。

    以上です。



 constraint_table.py



     
    という訳で、次回 は ... What's Next ...

      乞う、ご期待!! Stay tuned ..