スタジオブロス TECH BLOG

スタジオブロススタッフからの最新ツール情報やチュートリアル・TIPSなどを紹介します

基礎から始める3dsmax/Python(MaxPlus)プログラミング⑧

今週はこんなプログラムです。長いですが、コメントを詳細にしました。

import random, math, MaxPlus as mp
#-------------------- 0.0~1.0の範囲のfloat型の乱数を返す
def rnd():
 return random.random()
#-------------------- -3.14+乱数(0~1)*2*3.14=-3.14~13.14
def rndAngle():
 return -math.pi + (rnd() * 2 * math.pi)
#-------------------- クォータニオンの軸と角度をランダムに決める
def rndQuat():
 return mp.Quat(rnd(), rnd(), rnd(), rndAngle())
#-------------------- (0~1)*100-50=-50~50
def rndDist():
 return rnd() * 100.0 - 50.0
#--------------------座標のX,Yをランダムに
def rndPosition():
 return mp.Point3(rndDist(), rndDist(), 0)
#-------------------- (0~1)*2+1=1~3倍
def rndScaleAmount():
 return rnd() * 2.0 + 0.1
#--------------------XYZをランダムスケール
def rndScale():
 return mp.Point3(rndScaleAmount(), rndScaleAmount(), rndScaleAmount())
#-------------------- 移動、回転、スケールをランダムに
def randomTransformNodes(nodes):
 for n in nodes:
  n.Scaling = rndScale()
  n.Position = rndPosition()
  n.Rotation = rndQuat()
#-------------------- オブジェクト作成 ここでforで繰り返し作成
def createNodes(obj, cnt):
 return [mp.Factory.CreateNode(obj) for i in range(cnt)]
#-------------------- メイン関数
def main():
 box = mp.Factory.CreateGeomObject(mp.ClassIds.Box) 
 box.ParameterBlock.Length.Value = 10.0
 box.ParameterBlock.Height.Value = 10.0
 box.ParameterBlock.Width.Value = 10.0
 nodes = createNodes(box, 25)
 randomTransformNodes(nodes)
#-------------------- ジーンを初期化して実行
mp.FileManager.Reset(True)
main()

では、早速実行してみましょう。

実行の度に違うガレキの山ができます。これをアタッチして、岩のテクスチャを貼れば背景に使えそうですね。

26行目の

n.Scaling =rndScale()

と28行目の

n.Rotation =rndQuat()

を削除すると・・・

28行目の削除だけだと・・・

26行目の削除だけだと・・・

今回はランダム関数の塊です。位置、回転、スケールをランダムにして配置しています。

プログラムの書き方の例でもあります。複雑になって解らなくなるより、今回のように1行しかない関数を集めて作る方法をお勧めします。最初から解説します。

import random, math, MaxPlus as mp これは過去には3行で import random import math import MaxPlus as mp

と書いていましたが、このように書いてもOKです。 def rnd():で0.0~1.0の範囲のfloat型の乱数を作ります。 return random.random()は引数自体にランダムな数字を作るPythonの関数を入れて短く書いています。今回のプログラムは全てこの方法です。

次のrndAngle():が解りにくいかもしれません

return -math.pi + (rnd() * 2 * math.pi) math.piは3.14の円周率です。rnd() は0.0~1.0で変化する乱数です。難しい場合、最少と最大の値を入れてみるといいです。

最少:0・・・-3.14+0*23.14=-3.14 最大:1・・・-3.14+1*23.14=3.14 といことは、-3.14~3.14に変化する値になります。 クオータニオンは「ラジアン」で角度を計算しますから、3.14=180度ですから、-180から180度に回転できるので、1周しますね。

以下、同様です。 13行目 return rnd() * 100.0 - 50.0 ・・・-50~50=XYの位置 19行目 return rnd() * 2.0 + 0.1 ・・・1~3=スケール

今回は関数が連動しています。 rnd()→rndAngle()→rndQuat()→randomTransformNodes(nodes):→main(): rnd()→rndPosition()→randomTransformNodes(nodes):→main(): rnd()→rndScaleAmount()→rndScale()→randomTransformNodes(nodes):→main():

createNodes(obj, cnt)→main() 落ち着いて、プログラムの流れを読み取ってください。 一番今回特殊なのは、30,31行です。 createNodes(obj, cnt): return [mp.Factory.CreateNode(obj) for i in range(cnt)]

この1行でBOXを作成して、引数のcntをforで繰り返しているのです。 ちょっと癖のある書き方ですが、プログラミングはこのように様々な人の工夫を参考にすると早く覚えることができます。

注意なのは、createNodes(obj, cnt)mp.Factory.CreateNode(obj)は全然別物です。 この連載は基本AutodeskのHelpにあるサンプルを改良してチュートリアルを作っていますが、これは間違えやすい悪い例です。 mp.Factory.CreateNodeは3dsmaxの命令ですから変更できないので、できれば関数の名前を間違えにくいものにしましょう。

def main()は、Boxを定義して大きさを決め、コピー数を決めてrandomTransformNodes関数を呼んでいます。これも難しくないですね。

createNodes(box, 25)でBox25個がnodesに入ります。 randomTransformNodes(nodes)で25個の位置、回転、スケールを変更します。for命令で繰り返す必要はありません。

範囲を-500~500、コピー数を500にしてみました。

さらに距離5000で1万個です。自由に変化を付けることができます。

今回はここまでです。