mayaでpymelを使うための入門編　その１

# 始めに

まずmayaでスクリプトをいじりたいと思ったときに必須のこと、pythonやpymelを使う上で是非身に付けていただきたいことを記載していきたいと思います。
私としても今後忘れないために少しづつ増やしていく予定です。

環境としてはpythonはMayaにならって2.7、Mayaのバージョンは２０１５/２０１６を基準に記載いたします。
２０１７以降でも使えるスクリプト内容を目指しますが、スクリプトのバージョンが変わりますので絶対ではありません。

※一度投稿した記事も今後少しづつ画像を加えたりしてもっと良くなるように変更を加える場合がございます。

## 学ぶ上で絶対に見ておきたいもの

私が伝えるのはpythonですので pythonのドキュメントはまず見ておきたいところ
http://docs.python.jp/2.7/reference/index.html

そして何はともあれMayaのリファレンスです。
http://help.autodesk.com/view/MAYAUL/2015/JPN/
http://help.autodesk.com/view/MAYAUL/2016/JPN/

こちらはいつも見ないといけません、全部覚えきった！　などというのは気のせいです。
スクリプトとして良いものを書こうと思ったら眺めて仕組みを改めて考えて直して書き直してを繰り返します。
仕事の上ではそういった研鑽の時間を持つのは大変かもしれませんが１０分や２０分位は悩んでもいいのではないでしょうか。

次に、こちらはスクリプトを学ぶ上で私も教えていただき目から鱗になったものです。
python　を書く上でのコーディングスタイルの指標となる　pep8
http://pep8-ja.readthedocs.io/ja/latest/

※qiitaでいい記事がありますので引用
[Python のコーディング規約 PEP8 に準拠する](http://qiita.com/ynakayama/items/8616f4c0c6e372de9a42)

私は直接手法を教えていただいきましたが、こちらも同じ qiita でまとめていただいている変数の名前の付け方です。
[うまくメソッド名を付けるための参考情報](http://qiita.com/KeithYokoma/items/2193cf79ba76563e3db6)

これはとりあえず学び守れるところは守って書いてみましょう、すぐにその必然性を理解することになります。
インデントの使い方や改行、括弧の使い方等、コーディングスタイルや、作業環境の作成というものは適当にやっていると他の方のものを見た時や保守をするうえで大概大変な目に会います。

例えばコーディングスタイルがめちゃめちゃですと

- 自分のスクリプトが当時どんなに読みやすいと感じても後で読み返すと見づらい
- 後で読み返しても理解できない
- 意外と他のスクリプトに応用できない
    - キャストのやり方が汚い
    - 一行にまとめすぎたりして他の処理を挟む余地がない
    - 変数の名前がユニークになりすぎてその時にそぐわない
    - etc...
- 自身が書く独自のスクリプトに慣れすぎて他の方のスクリプトを読んでいてもすぐにわからない

また環境が無い場合

- その場で簡易実行ができず、トライ＆エラーまでの時間が長い
- スペルミスを指摘してくれないために変数のスペルミスに気付かない
    - そもそも補助機能によってそもそも記述速度を上昇させてくれる恩恵を受けられない
- unittest などの準備をしなければ効率化に伴い変更点があるといつまでも手動で頑張るデバックをすることになる
- etc...

やらないメリットは学習時間の短縮であったり、環境の準備時間そのものですが、当然やらなければ受けられない恩恵がそのままデメリットになります。
使い捨てや短いスクリプトでは当然不必要になることもあると思います。
しかし学んでおいて損は無いはずです。

## 最初のHallo world
まずはmayaでスクリプトエディタを起動しpythonタブからこれを書いて実行してみましょう。

```py:hallo_world.py
#!/usr/bin/env python
# coding=utf-8


def hallo_world():
    print("hallo world")


hallo_world()
```

スクリプトエディタに hallo world が表示されたでしょうか。
とても簡単ですね、しかし非常に大事な作業です。
細かくかみ砕いて説明します。

 - python自体の呼び出しと文字コードの設定

    ```
    #!/usr/bin/env python
    # coding=utf-8
    ```
ここはいわゆる「おまじない」と呼ばれるものです。文字コードの設定と書かれていますが、実はMayaで実行しているとこれが無くても問題が起きにくく（Maya自体が一部内包しているが故にエラーを出さないことがあるので）ちょっとわかりにくいです。
本来windowsのコマンドコンソール上でこういうのが設定されていないと print("いえすパイソン！") とかimport　ほにゃっほにゃ！とやったときにエラーを吐いてくれたりするのです、とりあえず宣言しておくと問題が起きにくくなります。
多少複雑なスクリプトになったときに他のファンクションを呼び出すことも多ければ、内容によってはasciiだったりunicodeだったりいろいろ混じってきますのでそういうときもあるんだと思ってください。
　
 - メソッドの設定

    ```
    def hallo_world():
    ```
ここで行っているのはファンクション、メソッド、関数などと呼ばれているものを設定しています。 
今後ちゃんと説明するかもしれませんが、その単語の詳細は別途調べてください、
まずはやってみようの精神で説明していきますので、この場では置いておきます。
　
 - 文章の標準出力

    ```
        print("hallo world")
    ```
まずインデントされていますが、defなどのメソッドやfor文、if分などの影響範囲下のブロックをpythonではインデントで示します。
なので余計にインデントしたり、逆にしないでおくとプログラムが範囲を認識できずにエラーでとまります。
ちなみに、文章をアウトプット（出力）する手法は様々ありますが、一番単純に他のスクリプトが受けとれる形であったり、とりあえずコンソールへ表示させる手法を標準出力と呼びます。
※上記二つですが詳細はやはり別途調べてください、以降この手の注釈は加えません。
　
 - 定義したメソッド、関数の呼び出し

    ```
    hallo_world()
    ```
最後に作った文章を出力する関数を呼び出しすことで、ここで初めて作成したメソッドが実行されます。正確にはスクリプトは「上から順に滝のように戻ることなく順に読まれます。」逆行することはありません。

なので上のスクリプトも正確にはこんな感じになります。

```py:hallo_world.py
#!/usr/bin/env python
# coding=utf-8

# 文字の種別が設定されたよー

def hallo_world():
    print("hallo world")

# ここでどんな関数があるのか一つ読み込んだよー

hallo_world()

# ハローワールドのメソッドが呼ばれたので「ここにその内容を代入」するよー

    print("hallo world")

# ハローワールドを出力したよー
```

という感じになります。
なのぜ今回では呼び出しとメソッドの前後を入れ替えれば当然メソッドが無いのに呼び出そうとしてエラーとなりますのでご注意ください。

## pymel入門その１　「ノードの取得」

```py:hallo_world.py
#!/usr/bin/env python
# coding=utf-8

import pymel.core as pm

pm.spaceLocator(name="test")

_nodes = pm.ls(selection=True)
print(_nodes)
# >>> [nt.Transform(u'test')]

print(_nodes[0])
# >>> test
```

コマンドの内容については初めのほうで張ったリファレンスのリンクから調べてください。
もしくはスクリプトエディターから　help(pm.ls)　などとやれば詳細が出てきます。
では内容へ移ります。

 - PyMEL を使えるようにする。

    ```
    import pymel.core as pm
    ```

    まず　pymel　を使う上でMayaから提供されているパッケージを読み込まないといけません。
    これもリファレンスにちゃんと記載されています。

    http://help.autodesk.com/view/MAYAUL/2015/JPN/?guid=GUID-2AA5EFCE-53B1-46A0-8E43-4CD0B2C72FB4
　
 - 選択されているノードを取得する

    ```
    _nodes = pm.ls(selection=True)
    print(_nodes)    # ※１
    # >>> [nt.Transform(u'test')]

    print(_nodes[0])    # ※２
    # >>> test
    ```

    上記スクリプトで大事なことがあります。
    ※１で ls を使って選択されているノードを取得できているように見えますが、表示されている内容が変に見えます。
    ※２のところで後ろに [0] を加えることでちゃんとノードを取り出せました。
    これは ls を使って受け取れるものがノードそのものではなく List と呼ばれるものが返ってくるからです。
    選択されているものが一個だろうが何個だろうが必ず List で返ってきます。
    このように関数を呼び出した時には「何が取得できるのか」というのは必ず意識して作業しましょう。
    わからなければとりあえず受け取り　type(_nodes)　などとやれば何が返ってきたかわかります。
    
    同じように実は上記で表示されている「 test　」はただの文字列ではありません。ちゃんと「 ノード 」としてprintされています。こちらにも type(_nodes[0])　とやってあげると理解ができます。
    決してただの文字列ではなく、ここで str()　や他の関数を通して文字列にキャストしない限りはノードして扱われます。

    逆に文字列をみてノードとしてどうにかできるとアトリビュート操作をしようとしたらストリングには使用できませんと怒られることがあるので注意しましょう。（文字列からあらためてノードを取得したい場合は pm.ls("test")　のようにしてあげると改めて取得できます。）
　

だいぶ前置きも長くなりその１の話が少しになりましたが、今回はここまでにします。
次回は実際の作業にも使うような具体的な内容に触れて書いていきます。

## その１のまとめ

１、リファレンスをみる
２、環境構築で手抜きしない（難しい内容にはなりますが、まずはエディタを用意するだけでも！）
３、スクリプトがどういった流れで進むのか理解する
４、関数を使う上でそいつがどんな動作をするのか調べる

以上です。
何かありましたらご指摘、ご質問、ご連絡なんでも下さいませ。
次回はもっと実際のスクリプトについて書いてまいりますのでよろしくお願いします。