表示・名前・色・ユーザ定義
3ds Max Python チートシート の章一覧
ノードの見た目と名札まわりの操作です。ほとんどが プロパティへの代入 で済みます。
表示 / 非表示
b = rt.getNodeByName("Box001")
b.isHidden = True # MXS: b.isHidden = true(true にするのは hide b と同じ)
b.isHidden # True
rt.hide(rt.getNodeByName("Sphere001")) # MXS: hide $Sphere001(ノード 1 つを渡す)
rt.unhide(rt.objects) # MXS: unhide objects(ObjectSet をそのまま渡せる、全部表示)
rt.hide/rt.unhideはノード 1 つでも、rt.objectsのようなオブジェクト集合(ObjectSet)でも渡せます。- 非表示のノードも
rt.objectsには含まれます。見えているものだけ欲しいときはnot o.isHiddenで絞ります。
フリーズ / 解除
b = rt.getNodeByName("Box001")
b.isFrozen = True # MXS: b.isFrozen = true(true にするのは freeze b と同じ)
b.showFrozenInGray = False # フリーズしても元の色で表示
rt.unfreeze(list(rt.objects)) # MXS: unfreeze objects
名前を変える
b = rt.getNodeByName("Box001")
b.name = "Crate" # MXS: b.name = "Crate"
for o in rt.selection: # 接頭辞を付ける
o.name = "PROP_" + o.name
for o in rt.objects: # 置換する(Python の str.replace)
o.name = o.name.replace("001", "_A")
o.nameは Python のstrなので、replace/upper/ スライス / 正規表現(re.sub)がそのまま使えます。
連番でリネームする
nodes = sorted(rt.objects, key=lambda o: o.pos.x) # X 座標の順に並べてから
for i, o in enumerate(nodes, start=1):
o.name = "Item_{:03d}".format(i) # Item_001, Item_002, ...
sorted(..., key=...)で並び順を決めてから番号を振ると、毎回同じ結果になります。- ⚠️ 3ds Max は 同じ名前のノードを許します。名前が重ならないことを保証したいなら
o.name = rt.uniqueName("Item_")のように代入します。ただし一意性が保証されるのは次のシーンノードが作られるまでの間だけです。
色(ワイヤフレームカラー)
import random
b = rt.getNodeByName("Box001")
b.wirecolor = rt.Color(255, 0, 0) # MXS: b.wirecolor = red
b.wirecolor.r # 255.0
reds = [o for o in rt.objects if o.wirecolor == rt.red] # 色で絞り込む(この時点では b が該当)
for o in rt.objects: # ランダムな色
o.wirecolor = rt.Color(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
-
色の成分は
.r/.g/.b(0〜255 の float)で読めます。成分だけ書き換えたいときは、posと同じく 取り出して戻す 必要があります。c = b.wirecolor c.r = 0 b.wirecolor = c -
rt.red/rt.green/rt.blue/rt.white/rt.blackなどの色定数も使えます。
ビューポートの表示プロパティ
b = rt.getNodeByName("Box001")
b.displayByLayer = False # 表示設定を[レイヤー別]ではなく[オブジェクト別]にする(先に外しておく)
b.boxMode = True # バウンディングボックス表示
b.xray = True # シースルー表示(UI では Alt + X)
b.backfaceCull = True # 裏面を表示しない
b.renderable = False # レンダリングしない
b.castShadows = False # 影を落とさない
- オブジェクトプロパティ(右クリック → [オブジェクトプロパティ])の項目は、ほとんどがノードのプロパティとして読み書きできます。
- [レイヤー別]の設定は 3 種類あります。
displayByLayerはxray/boxModeなどの表示設定、colorByLayerはwirecolor、renderByLayerはrenderable/castShadowsなどのレンダリング関連の設定に対応します。ノード側を変えても見た目が変わらないときは、対応する設定を確かめます。
ユーザ定義プロパティ(ノードにメモを持たせる)
b = rt.getNodeByName("Box001")
rt.setUserProp(b, "export", True) # MXS: setUserProp b "export" true
rt.setUserProp(b, "lod", 2)
rt.getUserProp(b, "lod") # 2(数値に自動変換される。⚠️ 下記)
rt.getUserPropVal(b, "lod", asString=True) # '2'(文字列のまま欲しいとき)
rt.getUserPropBuffer(b) # 全文(オブジェクトプロパティ > ユーザ定義の欄)
- ユーザ定義プロパティは シーンファイルに保存される ので、書き出し設定やツール用の目印を持たせるのに便利です。
- ⚠️
getUserPropは値を数値やブール値に 自動変換 します(1mのような値は時間として解釈されることもあります)。文字列のまま読みたいときはgetUserPropVal(..., asString=True)を使います。 - 3ds Max 2019.1 Update 以降では、
getUserProp/setUserPropの代わりにgetUserPropVal/setUserPropValを使うことが公式ヘルプで推奨されています。setUserPropValは文字列を既定で引用符付きで保存し、getUserPropValは読み出すときに文字列の先頭と末尾が引用符ならそれを取り除きます。
構造のあるデータを持たせる(JSON)
import json
b = rt.getNodeByName("Box001")
data = {"tags": ["prop", "wood"], "weight": 1.5}
rt.setUserProp(b, "myToolData", json.dumps(data, ensure_ascii=False)) # 1 行の JSON にして保存
loaded = json.loads(rt.getUserPropVal(b, "myToolData", asString=True)) # 読み戻す
- ユーザ定義プロパティは「キー = 値」の 1 行ずつのテキストです。
json.dumpsは既定で 1 行になるので、そのまま値として入れられます。 - ⚠️ JSON のトップレベルは辞書か配列にします。文字列だけを保存すると、前後が引用符に見えて
getUserPropValで外されることがあります。
落とし穴まとめ
- 非表示のノードも
rt.objectsに含まれる。 - 同じ名前のノードを作れてしまう。一意にしたいなら
uniqueName。 wirecolor.r = ...のような成分だけの代入は効かない(取り出して戻す)。- ノード側の表示設定が効かないときは[レイヤー別]の設定になっていないか確かめる。
getUserPropは自動で型変換する。文字列のまま欲しいならgetUserPropVal(..., asString=True)。
関連
- 条件でノードを集める: 「選択・取得」章
- レイヤ単位で表示を変える: 「階層・グループ・レイヤ」章
コメント