【maya python8限目】コーンをらせん状に配置して、先端をlocatorに向けよう!

mayapy08 python入門
過去セミナー再配信のお知らせ

過去2回のセミナーが期間限定でアンコール配信中です!
「MayaPython習得に苦しんだ過去の自分に教えてあげたい。。」調べてもわからなかったこと、教えて欲しかったことを、とことん詰め込みました。初心者の方はぜひご覧ください!

ツール作成の全体フローを最短距離で体験できます。スクリプト未経験の方におすすめ!
https://tutorials.cgworld.jp/set/2050

Mayaのオペレーションの自動化について徹底解説。様々な操作を自動化できるようになります
https://tutorials.cgworld.jp/set/2041

こんにちは!ビーバー@ゲーム業界歴約20年 です。maya python初心者の方のために、カンタン・わかりやすい解説サイトを作っています。

maya pythonの学習情報って少ないですよね。自分が骨を折った経験をもとに、maya python基礎を最速で習得できる10回のチュートリアルを作ってみたので参考にしていただければ幸いです。

今回は、8回目。手作業でやると時間がかかってしまう「らせん状の配置」について、スクリプトから一発で行う方法を紹介します。スクリプトは一度書くと、何度でも使えるのでとても便利ですよ!

このチュートリアルでわかること
  • らせん状の配置をスクリプトから行う方法
  • setAttr, Duplicate, parent コマンドの使い方
  • 複数のオブジェクトにconstraintを一括でかける方法

>> Pythonの勉強方法を知りたい方はこちらをどうぞ

※当サイトで紹介する商品は、アフィリエイトプログラムを利用しています。

コーンをらせん状に配置して、先端をlocatorに向ける

画像のようなシーンを使って進めていきます。

  • 原点にlocator1
  • その子供にpCone1
  • Y=20にlocator2 を配置
mayapy08_01

このシーンでコーンをらせん状に配置し、コーンの先端がY=20のlocator2を向くようにします。
下記のスクリプトを実行。

cone = "pCone1"
for i in range(15):
    cmds.setAttr("locator1.ry",i*45)
    cone2 = cmds.duplicate(cone)
    cmds.parent(cone2,w=True)
    cone2 = cone2[0]
    cmds.setAttr(cone2+".ty",i*1)
    
meshes = cmds.ls(type="mesh")
conetranses = cmds.listRelatives(meshes,allParents=True)

for trans in conetranses:
    aimcon = cmds.aimConstraint("locator2",trans,offset=(0,0,-90))
    cmds.delete(aimcon)
mayapy08_02
スクリプトの実行結果
ピヨちゃん
ピヨちゃん

おお~!一発でらせん状に配置された!

ハムちゃん
ハムちゃん

今回はちょっとスクリプトが長いね。解説に入る前に、
どのようなアプローチでコーンのらせん状配置を実現するか考えてみよう

解説

何かのモデルやモーションを作る時と同じで、
最初にどのような作り方をするか段取りを考えたうえで、スクリプトを書いていきます。
今回は以下のような段取りにしました。

コーンを原点にあるlocator1の子供にする

  • locator1を45度回転
  • コーンをduplicate、ペアレント解除
  • コーンの位置を上へずらす(処理がすすむにつれ、より高い位置にずらしていく)
  • この処理を繰り返す


最後に、コーンをまとめてlocator2に aimコンストレインする

これらを12行のスクリプトにしています。

スクリプトの構造

スクリプトの挙動を1行ずつ確認していきましょう。

行数   スクリプト    処理内容                    
1行目cone = “pCone1”pCone1を変数coneに代入
2行目for i in range(15):以下の処理を15回繰り返す。
iには0~14が入る
3行目␣␣␣␣cmds.setAttr(“locator1.ry”,i*45)locator のtyの値にi*45を代入
4行目␣␣␣␣cone2 = cmds.duplicate(cone)pCone1を複製してcone2に代入
5行目␣␣␣␣cmds.parent(cone2,w=True)cone2のペアレントを解除
6行目␣␣␣␣cone2 = cone2[0]cone2がリスト型になっているので
要素を取り出してcone2に代入
7行目␣␣␣␣cmds.setAttr(cone2+”.ty”,i*1)cone2のtyの値にi*1を代入
8行目meshes = cmds.ls(type=”mesh”)メッシュを取得してmeshesに代入
9行目conetranses = cmds.listRelatives(meshes,allParents=True)meshesの親のtransformノードを取得、
conetransesに代入
10行目for trans in conetranses:conetransesの要素に対して以下を実行
11行目␣␣␣␣aimcon = cmds.aimConstraint(“locator2”,trans,offset=(0,0,-90))locator2の方向に向くように
aimコンストレインを実行
12行目␣␣␣␣cmds.delete(aimcon)コンストレインノードを削除
ハムちゃん
ハムちゃん

それでは詳しく処理を見ていこう!

4行目:pCone1を複製してcone2に代入

ピヨちゃん
ピヨちゃん

1~3行は限目の内容だから、4行目からで大丈夫だよ!

ハムちゃん
ハムちゃん

オッケ~!じゃあ質問です。
4行目は複製したコーンをcone2に代入しています、どうしてでしょう?

行数   スクリプト    処理内容                    
4行目cone2 = cmds.duplicate(cone)pCone1を複製してcone2に代入
ピヨちゃん
ピヨちゃん

5行目以降でcone2に対して処理するから、、かな?

ハムちゃん
ハムちゃん

そうだね。4行目はfor文に入っていて、繰り返される処理なんだ。
pCone1は、合計15回duplicateされて、
複製されたコーンの名前は「pCone2~16」になるから、
名前が変わっても、以降の処理に対応できるように変数にしておくんだよ。

5行目:cone2のペアレントを解除

ここではcone2をペアレント解除して、ワールド直下にしています。

行数   スクリプト    処理内容                    
5行目cmds.parent(cone2,w=True)cone2のペアレントを解除

初出のコマンド parent() について見ていきましょう。

parent

その名の通り、ノード同士の親子付けを行うコマンドです。
()内の書き方を解説します。

cmds.parent(“子供にしたいオブジェクト”、”親になるオブジェクト”、フラグ=〇〇)

オブジェクト名は 文字列 で指定します。
例)cmds.parent( “locator1” , “pCube1” )

ハムちゃん
ハムちゃん

フラグ「w」は「world」の省略版、ワールドにペアレント化するフラグだよ。

6行目:リストの要素を取り出してcone2に代入

行数   スクリプト    処理内容                    
6行目cone2 = cone2[0]     cone2がリスト型になっているので
要素を取り出して改めてcone2に代入

ここではcone2[0]とすることで、リストから要素を取り出しています。

ピヨちゃん
ピヨちゃん

リストからの要素取り出しは、たしか5限目でやったなあ。。
ここはcone2のままじゃダメなの?

ハムちゃん
ハムちゃん

次の行でsetAttrを実行したいけど、
cone2はリスト型になってしまっているから、そのままでは実行できないんだよ。

ピヨちゃん
ピヨちゃん

次の行で処理ができるように、リストからあらかじめ取り出しておくんだね。

cone2の中身を確認してみましょう。
最初のシーンに対して、スクリプトの3~5行目のみを実行し、cone2をハイライト+実行します。

mayapy08_01
最初のシーン
scriptEditor
スクリプトの3~5行目のみを実行し、cone2をハイライト+実行

赤枠で示したように、[‘pCone2’]が返ってきました。[ ]に入っているので、リスト型になります。

cone2 = cone2[0] を実行してから、もう一度cone2を実行すると、、

scriptEditor

pCone2 と、[ ]が外れ、リストの中の要素を取り出すことができました。
次の行からは、この単体の要素に対して処理を行っていくのです。

7行目:cone2のtyの値にi*1を代入

行数   スクリプト    処理内容                    
7行目cmds.setAttr(cone2+”.ty”,i*1)   cone2のtyの値にi*1を代入
ピヨちゃん
ピヨちゃん

さっきのリストから取り出したコーンのtyに、setAttrで値を設定しているね。

ここも内容的には問題ないよ!

ハムちゃん
ハムちゃん

だいぶ慣れてきたね!
ちなみにここまでが2行目のfor文の処理だ。

for文で行っている処理はこの通りです。

  • locator1を45度ずつ回転
  • コーンをduplicate、ペアレント解除
  • コーンの位置を上へずらす(処理がすすむにつれ、より高い位置にずらしていく)
  • この処理を繰り返す

次の行からが、コーンをまとめてlocator2にaimコンストレインする処理になります。

8行目:メッシュを取得してmeshesに代入

行数   スクリプト    処理内容                    
8行目meshes = cmds.ls(type=”mesh”)メッシュを取得してmeshesに代入

ここではコーンを取得するために、typeフラグでメッシュのノードをシーンから探して、
変数meshesに代入しています。

ピヨちゃん
ピヨちゃん

lsコマンドのフラグの書き方はわかるんだけど、
mesh、みたいなノードのタイプ名ってどうやって調べるの?

ハムちゃん
ハムちゃん

lsコマンドのshowTypeフラグで調べることができるよ。

タイプ名の調べ方

cmds.ls(type=”○○”)のタイプ名(文字列)は、
lsコマンドのshowTypeフラグで調べることができます。

例えば、シーンのpCone2を選択して、下記のスクリプトを実行

print(cmds.ls(selection=True,showType=True))
scriptEditor

赤枠のように、[ノード名 , タイプ名] が返ってきます。

9行目:コーンのtransformノードを取得、conetransesに代入

行数   スクリプト    処理内容                    
9行目conetranses = cmds.listRelatives(meshes,allParents=True)meshesの親のtransformノードを取得、
conetransesに代入

meshesの中身はshapeノードのため、
その親のtransformノードを取得して変数conetransesに入れています。

ピヨちゃん
ピヨちゃん

親のtransformノードを取得しているのは、あとでaimコンストレインをかけたいからだね
親を取得するコマンドがlistRelativesかな?

ハムちゃん
ハムちゃん

そのとおり!

listReratives()

このコマンドでは、ノードの親や子を返してくれます。

cmds.listReratives(ノード名”,フラグ=〇〇)

「allParents」フラグは親を返すフラグです。

10行目:aimコンストレインを実行

行数   スクリプト    処理内容                    
10行目for trans in conetranses:     conetransesの要素に対して以下を実行
ピヨちゃん
ピヨちゃん

10行目は
listRerativesで取得した、複数のtransformノードに対して処理を行う、だね!

ハムちゃん
ハムちゃん

10行目も大丈夫だね。じゃあ11行目行ってみよう!

11行目:aimコンストレインを実行

行数   スクリプト    処理内容                    
11行目aimcon = cmds.aimConstraint(“locator2”,trans,offset=(0,0,-90))locator2の方向に向くように
aimコンストレインを実行

ここでは、conetranses のうちの一つの要素である trans
(中身はpCone*のトランスフォームノード)がlocator2の方向を向くように、
オフセット値を入れてaimコンストレインをかけています。

ピヨちゃん
ピヨちゃん

コマンドの名前はaimConstraint()、これは分かりやすいなあ

aimConstraint()

コマンド名の通り、エイムコンストレインを行うコマンドです。

cmds.listReratives(“コンストレインする側ノード名” , “される側ノード名” , フラグ=〇〇)

フラグはoffsetを指定しています。
フラグの書き方をヘルプで探すと、、引数タイプが[float, float, float]
これはどのように書けばよいのでしょうか?

mayaヘルプより
ハムちゃん
ハムちゃん

これはGUIからオプション設定するときの書き方と同じと考えると簡単だよ

aimConstraint_Option
ピヨちゃん
ピヨちゃん

そうか、赤枠のオフセット値と同じように書けばいいんだね!

あと、11行目では「コンストレイン実行」をaimconという変数に入れています。

aimcon = cmds.aimConstraint("locator2",trans,offset=(0,0,-90))

これはすなわち、コンストレインノードが「aimcon」に代入されているのです。

Outliner
ハムちゃん
ハムちゃん

コンストレインノードはこれだね!

12行目:コンストレインノードを削除

行数   スクリプト    処理内容                    
12行目cmds.delete(aimcon)      コンストレインノードを削除

「11行目で作成したコンストレインノード」を削除しています。

実行

ハムちゃん
ハムちゃん

それではドキドキの瞬間!スクリプトを実行しよう!

cone = "pCone1"
for i in range(15):
    cmds.setAttr("locator1.ry",i*45)
    cone2 = cmds.duplicate(cone)
    cmds.parent(cone2,w=True)
    cone2 = cone2[0]
    cmds.setAttr(cone2+".ty",i*1)
    
meshes = cmds.ls(type="mesh")
conetranses = cmds.listRelatives(meshes,allParents=True)

for trans in conetranses:
    aimcon = cmds.aimConstraint("locator2",trans,offset=(0,0,-90))
    cmds.delete(aimcon)
mayapy08_02
スクリプトの実行結果
ピヨちゃん
ピヨちゃん

できたよー!スクリプトの中身もちゃんとわかったよ!

まとめ

今回学習した内容のポイントをまとめます。

学習のポイント
  1. setAttr,Duplicate,parentなどを組み合わせて、オブジェクトを規則的に配置する
  2. リストから要素を抜き出して処理する
  3. ノードタイプは lsコマンドの showTypeフラグで調べることができる
  4. listRelativesコマンドを使って、親ノードを取得する
  5. aimConstraintコマンドで、方向コンストレインを設定する
ハムちゃん
ハムちゃん

ここまで勉強してきたことを組み合わせてみたよ!

次回は、作成したスクリプトをファイルに保存して、別のシーンから使ってみる、
という内容を解説します。お楽しみに!

はじめてpython学習するなら!

はじめてプログラミングを勉強するとき、エラーはつきものですよね。
何時間もスクリプトが動かないこともしばしば。。
そんな時、くわしい人に教えてもらいたい、と思うことはありませんか?

侍テラコヤは、はじめてpythonを学習する方にピッタリのサービスです。
サブスク型オンラインスクールで、月¥2980~の良心的なお値段!

現役エンジニアのサポートが充実しており、
オンラインのマンツーマンレッスンとQ&A掲示板で即座に悩みを解決することができます

maya python基礎

本サイトの【まとめ】 maya python 基礎 入門!では、
10回シリーズでmaya pythonの基礎が習得できるコンテンツを発信しています。

  • ちまたのスクリプトを読んで、内容を理解したい
  • mayaのスクリプトリファレンスの読み方を習得したい
  • 自分で簡単なツールを書きたい
  • 基礎的なmayaコマンドをpythonで使えるようになりたい

など、mayaでpython基礎を身に着けたい方は、ぜひご活用ください♪

オススメの本。pythonが楽しく学べます☆

復習はこちら↓

コメント

タイトルとURLをコピーしました