PySideでUSD関係のGUIを作ろう - SceneGraph(1)
最近PySideを触っていなくてすっかり頭から抜けてしまったので、リハビリがてらUsd関係の共通GUIを
作っていこうと思います。
まずはUsdのシーングラフをTreeViewで表示するためのModelを作って見ます。
完成はこんな感じ。
表示するデータ¶
#usda 1.0
def Xform "test"
{
def "hello"{}
def "world"{}
def "hoge"
{
def "fuga"{}
}
}
表示するUSDはこんな感じ。
とりあえずはシンプルな状態から。
ソースコード¶
長いけど全コード
# -*- coding: utf-8 -*-
import sys
import os.path
from PySide2.QtWidgets import (QApplication, QMainWindow, QTreeView)
from PySide2.QtCore import (QModelIndex, Qt, QAbstractItemModel)
from PySide2.QtUiTools import QUiLoader
from pxr import Usd, Sdf
sample_usd = "D:/work/usd_py36/usd/tree_view_sample.usda"
class UISample(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.resize(600, 400)
self.view = QTreeView()
self.ui = QUiLoader().load('D:/work/usd_py36/pysidse/tree_view.ui')
self.setCentralWidget(self.ui)
self.model = UsdStageModel(sample_usd)
self.ui.treeView.setModel(self.model)
class PrimItem(object):
def __init__(self, prim=None, parentItem=None):
self._prim = prim
self._parentItem = parentItem
self._childItems = []
def addChild(self, item):
self._childItems.append(item)
def getChild(self, row):
if row <= len(self._childItems):
return self._childItems[row]
return None
def getChildren(self):
return self._childItems
def getParentItem(self):
return self._parentItem
def getPrim(self):
return self._prim
def row(self):
return self._parentItem.getChildren().index(self)
def data(self, column):
if column == 0:
return self._prim.GetName()
if column == 1:
return self._prim.GetTypeName()
if column == 2:
return str(self._prim.GetPath())
class UsdStageModel(QAbstractItemModel):
header = ["PrimName", "Type", "SdfPath"]
def __init__(self, usdPath: str, parent=None):
super().__init__(parent)
# self.setupModelData(data.split('\n'), self.rootItem)
self.stage = Usd.Stage.Open(usdPath)
self.createModelTree()
def createModelTree(self):
# {SdfPath:Item}
self.rootItem = PrimItem(self.stage.GetPrimAtPath("/"), None)
prims = {Sdf.Path("/"): self.rootItem}
for prim in self.stage.Traverse():
print(prims)
parentPath = prim.GetParent().GetPath()
item = PrimItem(prim, prims[parentPath])
prims[parentPath].addChild(item)
prims[prim.GetPath()] = item
def columnCount(self, parent):
return 3
def data(self, index, role):
if not index.isValid():
return None
if role != Qt.DisplayRole:
return None
item = index.internalPointer()
return item.data(index.column())
def index(self, row, column, parent):
if not self.hasIndex(row, column, parent):
return QModelIndex()
if not parent.isValid():
parentItem = self.rootItem
else:
parentItem = parent.internalPointer()
childItem = parentItem.getChild(row)
if childItem:
index = self.createIndex(row, column, childItem)
return index
else:
return QModelIndex()
def parent(self, index):
if not index.isValid():
return QModelIndex()
childItem = index.internalPointer()
parentItem = childItem.getParentItem()
if parentItem == self.rootItem:
return QModelIndex()
return self.createIndex(parentItem.row(), 0, parentItem)
def rowCount(self, parent):
if parent.column() > 0:
return 0
if not parent.isValid():
parentItem = self.rootItem
else:
parentItem = parent.internalPointer()
return len(parentItem.getChildren())
def headerData(self, section, orientation, role):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self.header[section]
if __name__ == '__main__':
app = QApplication(sys.argv)
a = UISample()
a.show()
sys.exit(app.exec_())
以前にも作ったTreeViewの基本構造そのままです。
Modelに渡したUsdFileをTraverseして、Parent/Childの構造をつくります。
ItemにPrimObjectを入れて、そのItemを経由してViewに表示したい文字列を返すようにします。
コレを作る前は、
別にItem作らなくても、CreateIndexでPrimObjectをセットして、
GetParent()/GetChildren()使えばいいんじゃね?
と、試してみたのですが
その場合、internalPointerの部分で問答無用でスクリプトが落ちてしまい動きませんでした。
ポインタでオブジェクト取得してくる当たりが具合が悪いのか....
USDのリポジトリにはusdviewのソースコードも含まれているので
じゃあこちらはどうやってるのかなぁとみてみたら
pxr/usdImaging/lib/usdviewq/primViewItem.py
ここにコードがありました。
usdviewは、TreeWidgetつかってるのかぁとかWidgetItemで実装できるんだ、とか
色々と発見があったのですが
こちらでもItemにPrimObjectを入れて色々やっていたので
私もPrimItemを作る構造にしました。
次は¶
とりあえずこれで基本構造はできたので、今度はこれをGUI上から編集できるように
してみようとおもいます。
最終更新日: 2020-01-19 14:18:28