PyMELの応用 (岩石)

岩石を作る

ラティスデフォーマを利用した岩石を自動生成するスクリプトを作成してみましょう。

岩石を作る方法

ポリゴンにデフォーマをかけて全体がゆがんだ形になるようにしてみます。

今回の作り方は以下の通りです。

  1. ポリゴンの球を作ります。
  2. ラティスデフォーマを作成します。
  3. 乱数を 3 つ発生させます。
  4. その乱数で X, Y, Z 方向に、ラティスデフォーマにスケールをかけます。
  5. ラティスデフォーマの各制御点に対して以下の処理を繰り返します。
    1. 乱数を 3 つ発生させます。
    2. その乱数で制御点を X, Y, Z 方向に移動させます。

岩石を作るプログラム 2

まず、1 個だけ岩石を作るスクリプトを作ってみましょう。

  1. 以下の MEL スクリプトを Python スクリプトに書き直して、 makeRock4.py という名前で保存します。
    global proc makeRock4()
    {
    	polySphere;
    	string $lname[] = `lattice -divisions 2 5 2 -objectCentered true`;
    	float $x = rand(1.0, 3.0);
    	float $y = rand(1.0, 3.0);
    	float $z = rand(1.0, 3.0);
    	scale $x $y $z;
    	string $points[] = `filterExpand -selectionMask 46 ($lname[1] + ".pt[0:1][0:4][0:1]")`;
    	for($obj in $points)
    	{
    		$x = rand(-0.6, 0.6);
    		$y = rand(-0.6, 0.6);
    		$z = rand(-0.6, 0.6);
    		select -r $obj;
    		move -r $x $y $z;
    	}
    }
    
  2. 以下のプロシージャを makeRock4.py と言う名前でファイルに書き込みます。
    import pymel.core
    import random
    
    def makeRock4():
        pname = pymel.core.polySphere()
        lname = pymel.core.lattice(divisions=(2, 5, 2), objectCentered=True)
        x = random.uniform(1.0, 3.0)
        y = random.uniform(1.0, 3.0)
        z = random.uniform(1.0, 3.0)
        pymel.core.scale(x, y, z)
        points = pymel.core.filterExpand((lname[1] + '.pt[0:1][0:4][0:1]'), selectionMask=46)
        for obj in points:
            x = random.uniform(-0.6, 0.6)
            y = random.uniform(-0.6, 0.6)
            z = random.uniform(-0.6, 0.6)
            pymel.core.select(obj, r=True)
            pymel.core.move(x, y, z, r=True)
    
  3. スクリプト エディタ の ファイル → スクリプトのロード によって makeRock4.py を読み込んで、テンキーの Enter キーなどで実行します。
  4. スクリプト エディタ で以下のコマンドを実行してみます。
    makeRock4()
    [makeRock4() の実行例]

スクリプトの解説

import pymel.core
pymel.core モジュールをインポートします。
import random
random モジュールをインポートします。
uniform() 関数を使うために必要です。
def makeRock4():
makeRock4 という名前の関数を宣言します。
pname = pymel.core.polySphere()
ポリゴンの球体を作ります。
poly には球の名前が代入されます。 (poly[0] にトランスフォームノード、poly[1] にインプットノード)
lname = pymel.core.lattice(divisions=(2, 5, 2), objectCentered=True)
ラティスデフォーマを作成します。
[ラティスデフォーマ]
lname[0] に ffd ノード名、lname[1] にトランスフォーム名(ffd1Lattice など)、 lname[2] にトランスフォーム名(ffd1Base など)が入ります。
ffd ノードは、入力オブジェクトのコンポーネントを変形するノードです。
[ラティスデフォーマのノード]
divisions=(2
X, Y, Z方向のラティススライス数を設定します。
ここでは、X 方向に 2 分割、 Y 方向に 5 分割、 Z 方向に 2 分割しています。
objectCentered=True
選択されているポリゴンオブジェクトにラティスがセンタリングされます。 デフォルトは False なので、 このフラグをつけないとラティスデフォーマが原点でセンタリングされてしまいます。
x = random.uniform(1.0, 3.0)
1.0 から 3.0 の乱数の値をxに代入します。
y = random.uniform(1.0, 3.0)
1.0 から 3.0 の乱数の値をyに代入します。
z = random.uniform(1.0, 3.0)
1.0 から 3.0 の乱数の値をzに代入します。
pymel.core.scale(x, y, z)
3 つの乱数によってラティスデフォーマにスケールをかけます
points = pymel.core.filterExpand((lname[1] + '.pt[0:1][0:4][0:1]'), selectionMask=46)
ラティスデフォーマ lname[0] の制御点全部 .pt[0:1][0:4][0:1] を配列に展開して points[] に代入します。
selectionMask の 46 はラティスデフォーマの制御点を表します。
.pt[0:1][0:4][0:1] は、以下の 2 * 5 * 2 = 20 個の制御点を表します。
.pt[0][0][0]
.pt[0][0][1]
.pt[0][1][0]
.pt[0][1][1]
.
.
.pt[1][4][0]
.pt[1][4][1]
lname[1] に入っているラティスデフォーマの名前を ffd1Lattice とすると、 points[] には、以下のように ffd1Lattice の制御点の名前が代入されます。
points[0] = "ffd1Lattice.pt[0][0][0]"
points[1] = "ffd1Lattice.pt[0][0][1]"
points[2] = "ffd1Lattice.pt[0][1][0]"
points[3] = "ffd1Lattice.pt[0][1][1]"
.
.
points[18] = "ffd1Lattice.pt[1][4][0]"
points[19] = "ffd1Lattice.pt[1][4][1]"
for obj in points:
ラティスデフォーマの各制御点に対して、以下の処理を行います。
x = random.uniform(-0.6, 0.6)
-0.6 から 0.6 の乱数の値を$xに代入します。
y = random.uniform(-0.6, 0.6)
-0.6 から 0.6 の乱数の値を$yに代入します。
z = random.uniform(-0.6, 0.6)
-0.6 から 0.6 の乱数の値を$zに代入します。
pymel.core.select(obj, r=True)
制御点(obj)を選択します。
pymel.core.move(x, y, z, r=True)
ラティスデフォーマの制御点を、元の位置から x, y, z 移動します。
r フラグによって相対位置での移動になります。

Tips (seed)

random.uniform() 関数を使用すると、実行するたびに違う数値がかえってきますが、 常に同じ数値を返すようにしたい場合があります。 そのようなときには、以下のように random.seed() 関数を使用します。

random.seed(1)
random.uniform(1.0, 2.0)
# 結果: 1.1343642441124011 #
random.uniform(1.0, 2.0)
# 結果: 1.8474337369372327 #
random.seed(1)
random.uniform(1.0, 2.0)
# 結果: 1.1343642441124011 #
random.uniform(1.0, 2.0)
# 結果: 1.8474337369372327 #

練習

参考


Prev | Next
Home | Contents
Mail