生成・複製
3ds Max Python チートシート の章一覧
オブジェクトは クラス名を関数のように呼ぶ と作れます。パラメータはキーワード引数でまとめて渡せます。
プリミティブを作る
b = rt.Box(length=30, width=30, height=10) # MXS: box length:30 width:30 height:10
s = rt.Sphere(radius=15, segs=32, pos=rt.Point3(50, 0, 0)) # MXS: sphere radius:15 segs:32 pos:[50,0,0]
c = rt.Cylinder(radius=5, height=40, name="Pillar", wirecolor=rt.Color(200, 60, 60))
- 作成時のキーワード引数には、クラス固有のパラメータ(
radiusなど)とノード共通のプロパティ(name/pos/wirecolorなど)を混ぜて書けます。 - 作ったものはすぐにはビューポートに出ません。スクリプトの終わりか
rt.redrawViews()で描画されます。 - クラス固有のパラメータ(
radiusなど)はrt.getPropNames(b)で調べられます。ノードに対して呼ぶと基本オブジェクトのパラメータだけが返り、name/posなどノード共通のプロパティは含まれません(→「モジュール管理・デバッグ」章)。
名前が重ならないようにする
name = rt.uniqueName("Pillar") # MXS: uniqueName "Pillar" → "Pillar001" など
c = rt.Cylinder(name=name)
作れる主なクラスの例
# ジオメトリ
rt.Plane(length=100, width=100)
rt.Teapot(radius=10)
rt.Torus(radius1=20, radius2=5)
rt.GeoSphere(radius=10)
rt.Cone(radius1=10, radius2=0, height=20)
# ヘルパー
rt.Dummy(boxsize=rt.Point3(10, 10, 10))
rt.Point(size=20, cross=True, box=False)
# シェイプ(スプライン)
rt.Circle(radius=20)
rt.Rectangle(length=20, width=40)
rt.Text(text="Hello", size=20)
# ライト・カメラ
rt.Omnilight(pos=rt.Point3(0, 0, 100))
rt.Freecamera(pos=rt.Point3(0, -200, 50))
ターゲット付きのカメラ・ライト
target = rt.Targetobject(pos=rt.Point3(0, 0, 0))
cam = rt.Targetcamera(pos=rt.Point3(0, -200, 100), target=target) # MXS: targetcamera pos:[0,-200,100] target:(targetObject pos:[0,0,0])
cam.fov = 45
- ターゲットは先に
Targetobjectとして作り、target=に渡します。 - ⚠️ ターゲットをカメラに結び付けると、カメラを削除したときターゲットも一緒に削除されます。
スプラインを点から作る
points = [rt.Point3(0, 0, 0), rt.Point3(50, 0, 0), rt.Point3(50, 50, 0), rt.Point3(0, 50, 20)]
shp = rt.SplineShape(name="MyPath") # MXS: shp = splineShape name:"MyPath"
idx = rt.addNewSpline(shp) # 空のスプラインを追加(番号は 1 始まり)
for p in points:
rt.addKnot(shp, idx, rt.Name("corner"), rt.Name("line"), p) # MXS: addKnot shp idx #corner #line p
rt.updateShape(shp) # 変更を反映(忘れると形が出ない)
- 閉じた形にしたいときは、
updateShapeの前にrt.close(shp, idx)を呼びます。 - ノットの種類は
#smooth/#corner/#bezier/#bezierCorner、線分は#curve/#lineをrt.Nameで渡します。#bezier/#bezierCornerのときは、位置の後にイン/アウト ベクトルのハンドル座標も 2 つ渡す必要があります。
複製する(copy / instance / reference)
b = rt.getNodeByName("Box001")
c = rt.copy(b) # MXS: copy b(独立したコピー)
inst = rt.instance(b) # MXS: instance b(パラメータを共有)
r = rt.reference(b) # MXS: reference b(元の変更が伝わり、上にモディファイヤを足せる)
inst.pos = rt.Point3(40, 0, 0)
b.height = 50 # instance / reference にも反映される
- 複製は元と 同じ位置 に作られます。重なって見えないので、位置をずらして確認します。
オフセットを付けて複製する(cloneNodes)
b = rt.getNodeByName("Box001")
ok, clones = rt.maxOps.cloneNodes(
b,
offset=rt.Point3(30, 0, 0),
cloneType=rt.Name("instance"), # #copy / #instance / #reference
newNodes=pymxs.byref(None),
)
# MXS: maxOps.cloneNodes b offset:[30,0,0] cloneType:#instance newNodes:&nn
maxOps.cloneNodesは [編集] → [クローン] と同じで、ライトやカメラのターゲット、グループの一部といった従属ノードも一緒に複製され、元ノードと新ノードの対応はactualNodeList/newNodesで取れます。子も階層ごと複製したいときはexpandHierarchy=Trueを付けます(既定はFalseで子は複製されません)。新しいノードはpymxs.byrefで受け取ります(→「MaxScript との連携」章)。- ⚠️
undo offのコンテキスト内では使えません([元に戻す]機能を使ったときに 3ds Max がクラッシュします)。
並べて複製する
b = rt.getNodeByName("Box001")
clones = []
for i in range(1, 6):
n = rt.instance(b)
n.pos = b.pos + rt.Point3(i * 30, 0, 0)
n.name = "{}_{:02d}".format(b.name, i)
clones.append(n)
- Python の
formatで連番の名前を作れます(3ds Max 2022 の Python 3.7 では f 文字列も使えます)。
インスタンスを調べる・置き換える
b = rt.getNodeByName("Box001")
rt.instance(b)
rt.instance(b)
count, insts = rt.InstanceMgr.GetInstances(b, pymxs.byref(None)) # 自分を含むインスタンスの一覧
# MXS: InstanceMgr.GetInstances b &insts
names = [str(n.name) for n in insts]
s = rt.getNodeByName("Sphere001")
rt.instanceReplace(s, b) # s のオブジェクトを b のインスタンスに置き換える
# MXS: instanceReplace s b
instanceReplaceはsの名前・位置・マテリアルはそのままに、ジオメトリ(基本オブジェクトとモディファイヤ)だけをbと共有するインスタンスに置き換えます。
削除する
rt.delete(rt.getNodeByName("Teapot001")) # MXS: delete $Teapot001
rt.delete([o for o in rt.objects if rt.classOf(o) == rt.Sphere]) # まとめて削除
# MXS: delete (for o in objects where classOf o == Sphere collect o)
- 削除したノードを Python の変数で持ち続けていても、もう使えません。触る前に
rt.isValidNode(n)で確かめます。 - シーンを丸ごと空にしたいときは
rt.resetMaxFile(rt.Name("noPrompt"))(→「ファイル・データ」章)。
落とし穴まとめ
- 作っただけではビューポートに出ない。必要なら
rt.redrawViews()。 - 複製は元と同じ位置にできる。
instanceはパラメータを共有する。片方だけ変えたいならcopy。- スプラインは
updateShapeを呼ぶまで形が反映されない。
関連
- 作ったものを並べる: 「変形・配置」章
- 親子・グループ・レイヤにまとめる: 「階層・グループ・レイヤ」章
コメント