USDViewPluginで自作GUIを追加しよう
前回 で pluginInfo.json を書いて usdview にプラグインを追加することができたのですが、 今回はただ Print するだけではなく、今開いている Stage をゴニョゴニョするような処理を Plugin を利用して書いてみます。
フォルダ構成や plugInfo.json は前回と共通なのでスキップして本体のみ解説。 長いけど全コード
from pxr import Tf, UsdGeom
from pxr.Usdviewq.plugin import PluginContainer
from PySide2.QtWidgets import QDialog, QVBoxLayout, QPushButton
class TestDialog(QDialog):
def __init__(self, usdviewApi):
super().__init__(usdviewApi.qMainWindow)
self.resize(400, 200)
self.usdviewApi = usdviewApi
layout = QVBoxLayout()
self.setLayout(layout)
btn = QPushButton('ShowSelection')
btn.clicked.connect(self.showSelection)
layout.addWidget(btn)
btn = QPushButton('SnapShot')
btn.clicked.connect(self.viewportCapture)
layout.addWidget(btn)
btn = QPushButton('createPrim')
btn.clicked.connect(self.createPrim)
layout.addWidget(btn)
def showSelection(self):
print(self.usdviewApi.dataModel.selection.getPrims())
def viewportCapture(self):
img = self.usdviewApi.GrabViewportShot()
img.save("D:/capture.jpg")
self.usdviewApi.PrintStatus("Save Image -> D:/capture.jpg")
def createPrim(self):
prim = self.usdviewApi.stage.GetPrimAtPath("/createPrim")
if not prim.IsValid():
prim = self.usdviewApi.stage.DefinePrim("/createPrim")
childSize = len(prim.GetChildren())
xform = UsdGeom.Xform.Define(self.usdviewApi.stage, prim.GetPath().AppendChild(f"ChildNode_{childSize+1}"))
self.usdviewApi.dataModel.selection.setPrim(xform)
def printMessage(usdviewApi):
win = TestDialog(usdviewApi)
win.show()
class TutorialPluginContainer(PluginContainer):
def registerPlugins(self, plugRegistry, usdviewApi):
self._printMessage = plugRegistry.registerCommandPlugin(
"TutorialPluginContainer.printMessage",
"TestGUI",
printMessage)
def configureView(self, plugRegistry, plugUIBuilder):
tutMenu = plugUIBuilder.findOrCreateMenu("Tutorial")
tutMenu.addItem(self._printMessage)
Tf.Type.Define(TutorialPluginContainer)
usdview の Plugin に必要なのは
- PluginContainer を継承したクラス
- 上のクラスを Tf.Type.Define
この2つです。 この Container 内で Menu に新しい GUI を表示するコマンドを追加してみます。
この Menu を実行すると、
こんな感じの GUI が表示されます。
MainWindow を受け取る
usdview は Maya などと同じく PySide を利用して作られているので カスタム GUI を作りたい場合も Maya と同じく MainWindow を取得して その MainWindow を親にした Dialog を作成すれば OK です。
plugRegistry.registerCommandPlugin で登録した関数には 引数で pxr.Usdviewq.usdviewApi.UsdviewApi クラスオブジェクトを受け取ります。 このオブジェクトには、現在の USDView で開いている Stage や Window の情報、 CurrentFrame の値、View 設定などが含まれていて これらを利用して処理を書くことができます。
super().__init__(usdviewApi.qMainWindow)
PySide の MainWindow は usdviewApi.qMainWindow で取得できます。 今回は QDialog で Stage に対して色々操作をしたかったので QDialog には UsdviewApi オブジェクトを渡して __init__に対してそのオブジェクトの qMainWindow を渡すようにしました。
TreeView の Item を追加・選択
usdView の TreeView に対して何かをしたい場合は self.usdviewApi.dataModel を利用します。 この dataModel を使用すれば、選択中の Prim オブジェクトを取得したり、 指定の Prim を選択状態にしたりできます。
print(self.usdviewApi.dataModel.selection.getPrims())
選択中の Prim は、 selection.getPrims() で取得ができます。
ここで取得できるのは USD の Prim なので あとは単独のツールで書くのと同じく処理を書けば OK です。
prim = self.usdviewApi.stage.GetPrimAtPath("/createPrim")
if not prim.IsValid():
prim = self.usdviewApi.stage.DefinePrim("/createPrim")
childSize = len(prim.GetChildren())
xform = UsdGeom.Xform.Define(self.usdviewApi.stage, prim.GetPath().AppendChild(f"ChildNode_{childSize+1}"))
self.usdviewApi.dataModel.selection.setPrim(xform)
self.usdviewApi.stage で、現在の Stage を取得することができるので 新しい Prim を追加する場合などは、取得した Stage に対して DefinePrim であったり UsdGeom.Define(stage,"PATH") を利用して Prim を追加することができます。
TreeView に増やした Prim を選択状態にしたい場合は、
self.usdviewApi.dataModel.selection.setPrim(xform)
selection.setPrim(primObj)
このように setPrim で、選択したい Prim を指定します。
ViewPort の ScreenShot をつくる
この usdvieApi を利用すると、現在の Viewport のスクリーンショットをかんたんに取ることができます。
img = self.usdviewApi.GrabViewportShot()
img.save("D:/capture.jpg")
self.usdviewApi.PrintStatus("Save Image -> D:/capture.jpg")
GrabViewportShot() で、Viewport の QImage オブジェクトを取得できます。 ので、あとは save(Path) で
こんな感じで現在のスクショが保存できます。
まとめ
Menu 登録した関数の引数で、いろんな情報を受け取れるオブジェクトが渡されるので あとは stage から中を Traverse したり、選択 Prim になにかしたり かんたんにできることがわかりました。
https://graphics.pixar.com/usd/docs/Creating-a-Usdview-Plugin.html
usdviewApi で受け取れる内容については、公式 Docs の Using the Usdview API に まとめがあります。
usdView 自体はデフォルトだと編集することが難しい(Python コマンドががんばるしかない) ですが、拡張を入れればできることがかなり増えるので いろいろな使い方できそうです。