こんにちは!ビーバー@ゲーム業界歴約20年 です。maya python初心者の方のために、カンタン・わかりやすい解説サイトを作っています。
maya pythonの学習情報って少ないですよね。自分が骨を折った経験をもとに、maya python基礎を最速で習得できる10回のチュートリアルを作ってみたので参考にしていただければ幸いです。
今回は、8回目。手作業でやると時間がかかってしまう「らせん状の配置」について、スクリプトから一発で行う方法を紹介します。スクリプトは一度書くと、何度でも使えるのでとても便利ですよ!
※当サイトで紹介する商品は、アフィリエイトプログラムを利用しています。
コーンをらせん状に配置して、先端をlocatorに向ける
画像のようなシーンを使って進めていきます。
- 原点にlocator1
- その子供にpCone1
- Y=20にlocator2 を配置
このシーンでコーンをらせん状に配置し、コーンの先端が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)
おお~!一発でらせん状に配置された!
今回はちょっとスクリプトが長いね。解説に入る前に、
どのようなアプローチでコーンのらせん状配置を実現するか考えてみよう
解説
何かのモデルやモーションを作る時と同じで、
最初にどのような作り方をするか段取りを考えたうえで、スクリプトを書いていきます。
今回は以下のような段取りにしました。
コーンを原点にある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に代入
オッケ~!じゃあ質問です。
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(“子供にしたいオブジェクト”、”親になるオブジェクト”、フラグ=〇〇)
フラグ「w」は「world」の省略版、ワールドにペアレント化するフラグだよ。
6行目:リストの要素を取り出してcone2に代入
行数 | スクリプト | 処理内容 |
6行目 | cone2 = cone2[0] | cone2がリスト型になっているので 要素を取り出して改めてcone2に代入 |
ここではcone2[0]とすることで、リストから要素を取り出しています。
リストからの要素取り出しは、たしか5限目でやったなあ。。
ここはcone2のままじゃダメなの?
次の行でsetAttrを実行したいけど、
cone2はリスト型になってしまっているから、そのままでは実行できないんだよ。
次の行で処理ができるように、リストからあらかじめ取り出しておくんだね。
cone2の中身を確認してみましょう。
最初のシーンに対して、スクリプトの3~5行目のみを実行し、cone2をハイライト+実行します。
赤枠で示したように、[‘pCone2’]が返ってきました。[ ]に入っているので、リスト型になります。
cone2 = cone2[0] を実行してから、もう一度cone2を実行すると、、
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))
赤枠のように、[ノード名 , タイプ名] が返ってきます。
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]
これはどのように書けばよいのでしょうか?
これはGUIからオプション設定するときの書き方と同じと考えると簡単だよ
そうか、赤枠のオフセット値と同じように書けばいいんだね!
あと、11行目では「コンストレイン実行」をaimconという変数に入れています。
aimcon = cmds.aimConstraint("locator2",trans,offset=(0,0,-90))
これはすなわち、コンストレインノードが「aimcon」に代入されているのです。
コンストレインノードはこれだね!
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)
できたよー!スクリプトの中身もちゃんとわかったよ!
まとめ
今回学習した内容のポイントをまとめます。
ここまで勉強してきたことを組み合わせてみたよ!
次回は、作成したスクリプトをファイルに保存して、別のシーンから使ってみる、
という内容を解説します。お楽しみに!
オススメの本。pythonが楽しく学べます☆
復習はこちら↓
コメント