リファレンス / 3ds Max / 3ds Max Python チートシート

生成・複製

  • 3dsMax
  • Python
  • pymxs
  • チートシート
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 を呼ぶまで形が反映されない。

関連

← 3ds Max Python チートシート へ