2015年9月11日金曜日

Mayaスタディ PyMelとNumPy

引き続きレンダリング空間について調査中だがカラーチェッカーをスクリプトで作りたいと思っていたのでmayaのスクリプトも勉強中。

Melを今から覚えるのは抵抗があるし、行列を扱いたいのでPythonとNumpyで行こうと思う。

MelをPythonに移植したmaya.cmdではなく、PyMelを使用してみる。
PyMelはSIのpythonスクリプトのようにオブジェクトが帰ってくるので使いやすそう。
ただMaya自体よくわかっていないので習得には時間が掛かるかも。

PyMelメモ

参考
PyMEL for Maya — PyMEL 1.0.7 documentatio
mtazmi-Lab: [pymel] pymel始めました
PyMEL Tips



選択したものの名前表示

from pymel.core import *

#plane3を選択して実行
a = selected()[0]
print a.longName()    #|pPlane1|pPlane2|pPlane3
print a.name()   #pPlane3
#Mayaでの名前は階層になっている

名前から選択する

from pymel.core import *

select(clear=True)                     #選択を解除する
select('|pPlane1|pPlane2|pPlane3')     #選択する
select('|pPlane1|pPlane2|', add=True)  #追加選択する 

print selected()                       #選択されているものを表示
#[nt.Transform(u'pPlane3'), nt.Transform(u'pPlane2')]

オブジェクトをリストに追加

from pymel.core import *

objList = []                                #空のリスト作成
objList.append(PyNode('pPlane1'))           #オブジェクトを追加
objList.append(PyNode('|pPlane1|pPlane2'))  #オブジェクトを追加

#リストを表示
print objList
#[nt.Transform(u'pPlane1'), nt.Transform(u'pPlane2')]

アトリビュートとメソッドの一覧

from pymel.core import *
a = selected()[0]
print listAttr(a)  # 指定オブジェクトのアトリビュート一覧
print dir(a)       # 指定オブジェクトのメソッド一覧

位置の設定と位置の取得

from pymel.core import *

tf,sh = polyPlane()
tf.translate.set(0,2,0)           #移動値のセット

tf2,sh2 = polyPlane()
tf2.setParent(tf)

print tf2.attr("translate").get() #アトリビュートのtranslateから位置を取得
#[0.0, -2.0, 0.0]
print tf2.translate.get()         #アトリビュートのtranslateから位置を取得
#[0.0, -2.0, 0.0]

print tf2.getTranslation()        #getTranslation()メソッドで位置を取得
#[0.0, -2.0, 0.0]
print tf2.getTranslation('world') #getTranslation()メソッドで位置を取得(world)
#[0.0, 0.0, 0.0]

tm = tf2.getTransformation()      #TransformationMatrixを取得
print tm
#[[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, -2.0, 0.0, 1.0]]
print tf2.getTranslation('world') #TransformationMatrixから移動値を取得
#[0.0, 0.0, 0.0]

アトリビュートの追加と取得

from pymel.core import *

oTransf,oShape = polyPlane()

#floatのattr追加、セット、取得
oTransf.addAttr('attr1', at='float')
oTransf.setAttr('attr1', 2.0)
print transf.attr1.get()
#2.0

#文字列のatrr追加、セット、取得
oTransf.addAttr('attr2', dt='string')
oTransf.setAttr('attr2',"aaaaa")
print transf.attr2.get()
#aaaaa

#matrixのatrr追加、セット、取得
oTransf.addAttr('attr3', at='matrix')
oTransf.setAttr('attr3', [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16])
print transf.attr3.get()
#[[1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0], [9.0, 10.0, 11.0, 12.0], [13.0, 14.0, 15.0, 16.0]]

#float3のatrr追加、セット、取得
oTransf.addAttr('attr4', dt='float3')
oTransf.setAttr('attr4', [1,2,3])
print transf.attr4.get()
#(1.0, 2.0, 3.0)

#ベクター配列のatrr追加、セット、取得
oTransf.addAttr('attr5', dt='vectorArray')
oTransf.setAttr('attr5', [[1,2,3],[4,5,6],[7,8,9]])
print transf.attr5.get()
#[dt.Vector([1.0, 2.0, 3.0]), dt.Vector([4.0, 5.0, 6.0]), dt.Vector([7.0, 8.0, 9.0])]

#アトリビュートの存在を調べる
print oTransf.hasAttr("attr5"), oTransf.hasAttr("attr100")
#True False

#アトリビュートの削除
oTransf.deleteAttr("attr5")

子供にする

from pymel.core import *
  
a = PyNode('pPlane1')                    #親にしたいやつをオブジェクトにする
b = PyNode('|pPlane1|pPlane2|pPlane3')   #子供にしたいやつをオブジェクトにする
a.addChild(b)

print b.longName()
#|pPlane1|pPlane3a

親にする

from pymel.core import *

a = PyNode('pPlane1')                  #親にしたいやつをオブジェクトにする
b = PyNode('|pPlane1|pPlane2|pPlane3') #子供をオブジェクトにする

b.setParent(a)                         #親をセットする
print b.longName()
#|pPlane1|pPlane3

親を取得

from pymel.core import *
 
a = PyNode('|pPlane1|pPlane2|pPlane3')    #オブジェクトを取得
print a.getParent()                       #親を取得 #pPlane2
print a.getParent().getParent()           #親の親を取得 #pPlane1
 
#ちなみにこれでも行けた
print a.getParent(0)     #自分を取得 #pPlane3
print a.getParent(1)     #親を取得 #pPlane2
print a.getParent(2)     #親の親を取得 #pPlane1

#親をすべて取得する場合はこれ
parentsList = a.getAllParents()
print parentsList    #[nt.Transform(u'pPlane2'), nt.Transform(u'pPlane1')]

マテリアル作成と割り当て

from pymel.core import *

#ランバートのマテリアルを新しく作って、一個選択されているものに割り当てる
sel = selected()[0]
shader , shadingEngine = createSurfaceShader("lambert")
sets(shadingEngine,forceElement=sel)

print shader
#lambert2
print shadingEngine
#lambert2SG
'''
SurfaceShaderというのはSIのマテリアルのsurfaceに指すシェーダーのようなもの?
[シェーダー名SG]というのは何?マテリアル?
'''

使用しているマテリアルの取得

上のシーンでpPlane2に新規ランバートを割り当て、pPlane2を選択して実行した
from pymel.core import *

#シェイプで使用しているSG?というものが取得できる
oShape = selected()[0].getShape()
sg = oShape.outputs(type='shadingEngine')

print sg[0]
#lambert2SG

'''
lambert2SGというのが取得できる
ハイパーグラフで見るとシェイプの先にlambert2SGに繋がっているのでoutputsプロパティで取得できる。
多分SGはシェーディンググループのことで、サーフェイス、ボリュームディスプレイスを入力に持つマテリアルのこと。
シェーディングエンジンってシェーディンググループと同じこと?
'''

sg = oShape.shadingGroups()
print sg[0]
#lambert2SG
'''
これでも同じものがとれた
'''

#SGが繋がっているものを取得してみる
oConnections = sg[0].connections()
for elem in oConnections:
    print elem

'''
lightLinker1
materialInfo1
lightLinker1
renderPartition
lambert2
pPlane3
pPlane2
'''
#SGが共有されているシェイプのトランスフォームノードも含まれている

#下記はSGのサーフェイスシェーダーに接続されているものを取得する方法
print sg[0].surfaceShader.connections()[0]
#lambert2



子供を取得

from pymel.core import *

obj = PyNode('pPlane1')
oChildren = obj.getChildren()
for Child in oChildren:
    print Child

'''
pPlaneShape1
pPlane2
pPlane3

pPlaneShape1ってなんだ?
nodeTypeというのを確認
'''
for Child in oChildren:
    print Child.nodeType()

'''
mesh
transform
transform

pPlaneShape1はmeshというノードタイプらしい。
それ以外は
mayaの場合これらも自身の子供として取得されてしまう。
なのでノードタイプでマスクする必要がある。
(getChildren()でマスク機能はないのかな?)
'''
for Child in oChildren:
    if Child.nodeType() == "transform":
        print Child
'''
pPlane2
pPlane3
'''

子孫を取得

#一つ選択してその子孫をノードタイプを指定して取得(ここではpPlane1選択後に実行)
from pymel.core import *

def getDescendants(obj,nType):
    oChildren = obj.getChildren()
    for Child in oChildren:
        if Child.nodeType() == nType:
            objList.append(Child)
        getDescendants(Child,nType)
    return objList

obj = selected()[0]
objList = []
print getDescendants(obj,"transform")
#[nt.Transform(u'pPlane2'), nt.Transform(u'pPlane4'), nt.Transform(u'pPlane5'), nt.Transform(u'pPlane3')]

削除

複数オブジェクトの削除の例

from pymel.core import *

objs = [PyNode('pPlane1'),PyNode('pPlane3')]
delete(objs)

matrixを作成

import pymel.core as pm

m = pm.datatypes.Matrix([[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]])
#or
m = pm.datatypes.Matrix(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)

PyMelMatrix to NumPyMatrix

import pymel.core as pm
import numpy as np

#PymelMatrix
m = pm.datatypes.Matrix([[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]])
#toNymPyMatrix
a = pm.datatypes.Matrix([[m[0,0],m[0,1],m[0,2],m[0,3]],
                         [m[1,0],m[1,1],m[1,2],m[1,3]],
                         [m[2,0],m[2,1],m[2,2],m[2,3]],
                         [m[3,0],m[3,1],m[3,2],m[3,3]]])


NumPyメモ


NumpyをMayaのPythonで使えるようにする
[GUIDE] Numpy+Scipy for Maya Windows 64 bit
このページのリンク先のNumpyを解凍して"\ProgramFiles\Autodesk\Maya2016\Python\Lib\site-packages"に入れただけ


参考
私訳「暫定的 NumPy チュートリアル」 - naoya_t@hatenablog
良いもの。悪いもの。: SciPyの使い方: 行列演算
python/numpy - 機械学習の「朱鷺の杜Wiki
NumpyとScipy

モジュールをインポートする書き方

#安全性◎ 手間× | 都度numpy.を付ける
import numpy
a = numpy.array([1,2,3])

#安全性◎ 手間○ | 任意の省略文字に置き換える。この場合都度np.を付ける(よく使われている)
import numpy as np
a = np.array([1,2,3])

#安全性× 手間◎ | 他モジュールと名前の衝突が起こる可能性が或る
from numpy import *
a = array([1,2,3])

#安全性〇 手間◎ | 衝突を避けるため必要なものを部分的にしか読み込まない。
from numpy import array,linalg
a = array([1,2,3])
length = norm(a)

Numpyの配列

numpy.array(リスト)
from numpy import *
 
arr = array( [0, 1, 2, 3, 4, 5] )    #0,1,2...5までの配列を作る
arr = array( [0, 1, 2, 3, 4, 5], dtype=int64 ) #dtypeを指定する場合
print arr                 #[0 1 2 3 4 5]
print len(arr)            #配列の要素数 #6
print arr[3]              #3番目の要素 #3
print arr[3:]             #3番目以降の要素 #[3 4 5]
print arr[1:4]            #1番目から3番目の要素 #[1 2 3]
arr[1:4] = 0,-1,100       #1番目から3番目の要素変更
print arr                 #[  0   0  -1 100   4   5]
print (where(arr>0,arr,3))#0より大きいものは3  #[  3   3   3 100   4   5]
print sort(arr)           #ソート #[ -1   0   0   4   5 100] 

NumPyの2次元配列

from numpy import *

#2次元配列の作成(型の指定つき)
a = array([[12,11,10,9],
           [8,7,6,5],
           [4,3,2,1]],dtype=float)

print a
'''
[[ 12.  11.  10.   9.]
 [  8.   7.   6.   5.]
 [  4.   3.   2.   1.]]
'''
a = a.astype(int32) #後から型を変えることも可能
print a
'''
[[12 11 10  9]
 [ 8  7  6  5]
 [ 4  3  2  1]]
'''
print a.ndim        #次元数
#2
print a.size        #サイズ
#12  
print a.shape       #次元の要素数
#(3L, 4L)
print a.dtype       #要素のデータ型
#int32
print a[0]          #0行目の取得
#[12 11 10  9]
print a[:,0]        #0列目の取得
#[12  8  4]
print a[0][0]       #0行目0列目の取得
#12
print a*a           #掛け算。行列の掛け算ではないので注意
'''
[[144 121 100  81]
 [ 64  49  36  25]
 [ 16   9   4   1]]
'''
print sqrt(a)       #平方根
'''
[[ 3.46410162  3.31662479  3.16227766  3.        ]
 [ 2.82842712  2.64575131  2.44948974  2.23606798]
 [ 2.          1.73205081  1.41421356  1.        ]]
'''
print sort(a)                  #ソート
'''
[[ 9 10 11 12]
 [ 5  6  7  8]
 [ 1  2  3  4]]
'''
print sort(a, axis=0)          #列でソート
'''
[[ 4  3  2  1]
 [ 8  7  6  5]
 [12 11 10  9]]
'''
print sort(sort(a), axis=0)    #行でソートした後に列でソート
'''
[[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]]
'''
print sort(a, axis=None)       #1次元としてでソート
#[ 1  2  3  4  5  6  7  8  9 10 11 12]

for i,elem in enumerate(a):    #インデックスも取得できる
    print i,elem
'''
0 [12 11 10  9]
1 [8 7 6 5]
2 [4 3 2 1]
'''
print a.sum()   # 合計
#78
print a.max()   # 最大値
#12
print a.min()   # 最大値
#1

reshape

from numpy import *

a = numpy.arange(0, 12, 1)
print a
#[ 0  1  2  3  4  5  6  7  8  9 10 11]

print a.reshape(2, 6)
'''
[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]]
'''

print a.reshape(4, 3)
'''
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]
'''

Numpyでベクトル演算

配列を使うだけ。
from numpy import *
v1 = array( [ 1, 2, 3 ] )
v2 = array( [ 0, -1, 2 ] )

print v1 + v2             #足し算 [1 1 5]
print v1 * v2             #要素の掛け算 [0 -2 6]
print dot(v1,v2)          #内積 4
print cross(v1,v2)        #外積 [ 7 -2 -1]
print linalg.norm(v1)     #長さ 3.74165738677
print v1/linalg.norm(v1)  #正規化 [ 0.26726124  0.53452248  0.80178373]

行列はmatrix

リストまたは文字列から作成する
from numpy import *

print(matrix('1 2 3'))               #1×3行列を文字列から作成
#[[1 2 3]]
print(matrix([1,2,3]))               #1×3行列をリストから作成
#[[1 2 3]]
print(matrix('1; 2; 3'))             #3×1行列を文字列から作成
'''
[[1]
 [2]
 [3]]
'''
print(matrix([[1],[2],[3]]))         #3×1行列をリストから作成
'''
[[1]
 [2]
 [3]]
'''
print(matrix('1 2 3; 4 5 6; 7 8 9')) #3×3行列を文字列から作成
'''
[[1 2 3]
 [4 5 6]
 [7 8 9]]
'''
print(matrix([[1,2,3],[4,5,6],[7,8,9]])) #3×3行列をリストから作成
'''
[[1 2 3]
 [4 5 6]
 [7 8 9]]
'''

配列と行列を間違えないこと

似てるけど掛け算すると値は違う
from numpy import *

arr =  array([[ 1,  2,  3],
              [ 4,  5,  6],
              [ 7,  8,  9]])
       
mat = matrix([[ 1,  2,  3],
              [ 4,  5,  6],
              [ 7,  8,  9]])

print arr.shape #各要素数
#(3L, 3L)
print mat.shape #各要素数
#(3L, 3L)

print arr + arr #配列の足し算
'''
[[ 2  4  6]
 [ 8 10 12]
 [14 16 18]]
'''
print mat + mat #行列の足し算
'''
[[ 2  4  6]
 [ 8 10 12]
 [14 16 18]]
'''

print arr * 3   #配列を定数倍
'''
[[ 3  6  9]
 [12 15 18]
 [21 24 27]]
'''
print mat * 3   #行列を定数倍
'''
[[ 3  6  9]
 [12 15 18]
 [21 24 27]]
'''

print arr * arr #配列の掛け算
'''
[[ 1  4  9]
 [16 25 36]
 [49 64 81]]
'''
print mat * mat #行列の掛け算
'''
[[ 30  36  42]
 [ 66  81  96]
 [102 126 150]]
'''

配列でも行列の演算はできた

配列の場合で行列の掛け算を行うにはdot関数を使う。行列演算の他の関数も使用できる。
from numpy import *

arr =  array([[ 1,  2,  3],
              [ 4,  5,  6],
              [ 7,  8,  9]])
       
mat = matrix([[ 1,  2,  3],
              [ 4,  5,  6],
              [ 7,  8,  9]])

print arr.dot(arr) #配列でも行列の掛け算ができる arr * arr はダメ
'''
[[ 30  36  42]
 [ 66  81  96]
 [102 126 150]]
'''
print mat * mat    #行列の掛け算 mat.dot(mat) でも良い
'''
[[ 30  36  42]
 [ 66  81  96]
 [102 126 150]]
''

行列を配列に格納する場合

from numpy import *
#arrayの中に入れるとうまくいかなかったのでリストにする。またはリストにappendで入れていく。
a = [
matrix('1 2 3; 4 5 6; 7 8 9'),
matrix('10 20 30; 40 50 60; 70 80 90'),
matrix('-1 -2 -3; -4 -5 -6; -7 -8 -9')
]
 
for i,elem in enumerate(a):
    print i ,repr(elem)

''' 
0 matrix([[1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]])
1 matrix([[10, 20, 30],
        [40, 50, 60],
        [70, 80, 90]])
2 matrix([[-1, -2, -3],
        [-4, -5, -6],
        [-7, -8, -9]])
'''

行列の演算


from numpy import *
 
a = matrix([[ 1,  2,  3],
            [ 4,  5,  6],
            [ 7,  8,  9]])
        
b = matrix([[ 9,  8,  7],
            [ 6,  5,  4],
            [ 3,  2,  1]])
                       
print a * b          #行列積 a.dot(b) でもよい
'''
[[ 30  24  18]
 [ 84  69  54]
 [138 114  90]]
'''
 
print a.I            #逆行列 linalg.inv(a) でもよい
'''
[[ -4.50359963e+15   9.00719925e+15  -4.50359963e+15]
 [  9.00719925e+15  -1.80143985e+16   9.00719925e+15]
 [ -4.50359963e+15   9.00719925e+15  -4.50359963e+15]]
'''
 
print a.T            #転置行列 transpose(a) でもよい
'''
[[1 4 7]
 [2 5 8]
 [3 6 9]]
'''
 
print a.diagonal()   #対角要素をベクトル化 diagonal(a)
#[[1 5 9]]
 
vec = a.diagonal()                #対角要素をベクトル化
c = matrix(zeros((3, 3), int))    #代入用のマトリクス作成
fill_diagonal(c,vec)              #対角要素をマトリクスへ代入
print repr(c)
'''
matrix([[1, 0, 0],
        [0, 5, 0],
        [0, 0, 9]])
'''

v = array([2,4,6])              
print a.dot(v)                    #行列とベクトルの積
#[[ 28  64 100]]

0 件のコメント:

コメントを投稿