USD での Composition の機能について.
Compositon Arcs(合成の環)というたいそうな名前が付いていてややこしいです.
コンポジションアークとは
https://fereria.github.io/reincarnation_tech/11_Pipeline/01_USD/05_comp_arc/
ありがとうございます.
種類
- subLayers (root の Stage/Layer meta でのみ)
- inherits
- references, payload
- variants(variantSet, variantSets)
- specializes
- (over)
subLayers
C++ での include のようなもの.
細かいところでは LayerOffset(T.B.W.) を指定できたりする.
inherits
C++ での継承のようなもの.PrimSpec meta で指定
Path で継承したい PrimSpec を指定.
文法上は複数指定できたり, ListEditing 点けたり出来るがどう解釈されるんでしょうかね.
e.g.
add inherits = [</base>, </bora>]
references
Maya, Max とかでの xref みたいなもの.
subLayers のように外部の usd ファイルを取り込める.
append, prepend で先に読むかあとで読むかも指定できる.
ただ, prepend にしても attribute の上書きはできないです(下記 LIVRPS 参照)
#usda 1.0
def Cube "cube0" {
double size = 4.0
}
#usda 1.0
def Cube "cube0" (
append references = @cube.usda@</cube0>
)
{
double size = 10
}
とあると,
usdcat references-prepend-cube-000.usda
#usda 1.0
def Cube "cube0" (
append references = @cube.usda@</cube0>
)
{
double size = 10
}
と, Local のほうが強いので Local attribute の設定 size = 10
が採用されます.
local の設定を上書きしたい場合は, over
を使うしかない... カナ?
payload
references
と似ているが遅延ロードできる.
variant
キーワードが 3 つあってややこしいです.
variants, variantSets は PrimSpec の metadatum で指定.
variants
, variantsets
(最後に s
が付くことに注意) は PrimSpec meta で指定し, どれが variant になるかを指定する感じ.
variantSet
(s
が無いことに注意) は PrimSpec の本体(?)で指定し, 実際に切り替えできる要素を指定する.
variantSet には PrimSpec の階層構造を持つこともできる. また再帰的に variantSet
を使うこともできる.
prim の meta も定義できる.
variantSet "shapeVariant" = {
"Capsule" ( active = true ) {
def Capsule "Pill"
{
}
}
ただ, variantSet
は Meta に定義することはできない
# NG
#usda 1.0
(
defaultPrim = "hello"
)
def Xform "hello" (
variants = {
string shadingVariant = "green"
string bora = "red"
}
prepend variantSets = "shadingVariant"
variantSet = { "bora" { active = true } }
)
{
}
Path での指定
{variantname=value}
で指定できます.
e.g.
``/Root/Child/Grandchild{modelingVariant=withCargoRack}/GreatGrandchild>`
Specializes
C++ のテンプレート特殊化みたいなもの.
あんまり使われることはない?...
over
over "myprim" {
...
}
で, def "myprim"
の設定を上書きすることができます.
対象となる prim がない場合は, 具現化(シーン(Stage)のプリミティブとしては現れない)
ただ, over と def は同じ名前(path)では USD 内では共存できません. subLayers, references などで外部を読み込んだものに対してのみ over は作用します
#usda 1.0
# NG
def Cube "cube0" {
double size = 4.0
}
over Cube "cube0" {
double size = 5.0
}
#usda 1.0
# OK
(
subLayers = [@cube.usda@]
)
over Cube "cube0" {
double size = 5.0
}
usdcat で --flatten
で合成すると, cube0
は def になり size 5.0 になります.
$ usdcat --flatten over-cube-001.usda
#usda 1.0
(
doc = """Generated from Composed Stage of root layer /mnt/data/work/tinyusdz/tests/usda/over-cube-001.usda
"""
)
def Cube "cube0"
{
double size = 50
}
over で Prim のタイプ(Cube, Mesh, ...)が指定されない場合は def
の設定を利用します.
over でタイプを変えることもできます.
たとえば↑で
over Sphere "cube0"
{
...
}
とすると Sphere プリミティブに変わります.
(ただ, Schema が合わない property になった場合は usdview などでなんかエラーがでるかもしれません)
ListEditing
たとえば references で usd を読み込む場合, PrimSpec(def
とかでのローカル定義) より 先に読み込むか(prepend), あとで読み込むか(append)を指定できます. delete
で削除というのもあります...
合成の評価順
LIVRPS 原則に基づく.
https://graphics.pixar.com/usd/release/glossary.html#livrps-strength-ordering
https://fereria.github.io/reincarnation_tech/11_Pipeline/01_USD/05_comp_arc/#livrps
Local, Inherits, VariantSets, References, Payloads, Specializes
リヴレプスと覚えましょう.
USD からみたとき, 呼び出し順は L, I, V, ... で, 評価(解決)の順は S, P, R, ... という感じ?
めんどいネ...
ただ, VariantSet では Specializes は処理されません.
references, payload の場合, ListEditing の append, prepend も影響する気がする?
評価のタイミングについて
USDA, USDC を読んだ時点では実際には合成処理は行わず, Flatten
操作で合成が行われます.
(Compose
とかの名前のほうがシックリくる気がするけど..)
payload
のある場合は, 実際にデータが必要になったときにロードと合成処理(Maya とかでの xref と同じ)が行われる.. はず.
また, Asset Resolver(アセットファイルの探索とか管理)のステートにも依存します(同じファイル名であるが, アセットの基点ディレクトリを変えることで異る中身の USD を呼んだりとかもあり得る)
Stack, Index 用語
ややこしいですが, pxrUSD での Stack は順序あり配列(std::stack
みたいなスタック構造ではなくて, std::list
相当),
Index は整数インデックス(id)ではなくて, Composite したあとの結果を指すオブジェクト, という意味合いです.
LayerStack
順序ありの Layer のリストです.
順序は subLayers
とかでの配列での定義順です.
自分自身が最上位になります.
たとえば sublayers-001.usda
が以下になっていると,
#usda 1.0
(
subLayers = [
@suzanne.usda@,
@cube-000.usda@,
@cone-000.usda@
]
)
LayerStack は
のようになります.
PrimSpec, PrimIndex, PrimStack
PrimSpec : Composite 前の状態(USD に記載された"部品"の状態)
Prim : 合成後に実際に出来た Prim
PrimStack : PrimSpec の配列(リスト)
PrinIndex : PrimSpec, PrimSpec などを Composite して評価したあとの状態. 最終的に PrimIndex を評価して Prim ができあがる感じ?
PropertyStack
Property も Stack がありますが,
Value resolution(実際にアトリビュート値を取得)には使わず, デバッグなど用です
実装者からみての処理
TinyUSDZ で Composition の処理を考えます.
自レイヤー : いわゆる USD ファイル
W.I.P.
- 最初に読み込まれる USD をパースする(これを "自レイヤー"とする)
以下を再帰的に処理していく.
- 自レイヤーの subLayers を解決(USD ファイル読み込み)
- 自レイヤーの Specializes を解決
- 自レイヤーの Payload を解決(読み込みがリクエストされたら)
- 自レイヤーの References を解決
- 自レイヤーの VariantSet を解決
- 自レイヤーの Inherits を解決
- 自レイヤーの
over
PrimSpec を解決
Crate format
Variant がややこしいです.
それ以外は straightforward な感じです.
References
Reference
という型が用意されています.
customData 対応
Payload
Payload
という型が用意されています. ほぼ Reference
と同じです.
0.8.0 から LayerOffset 対応
customData は対応していません.
Variant
VariantSelectionMap
: map<string, string>
SpecTypeVariant, SpecTypeVariantSet があります.
variantSet 内の Prim, Attribute はそのままいつもの Field 定義のようですが... T.B.W.
Inherits
PrimSpec metadataum に inherits
, inheritPaths
があります.
inheritPaths
は内部での整合性チェック用でしょうか.
Specializes
こちらも PrimSpec metadatum に specializes
があるだけです.
USDZ AR 拡張(sceneLibrary)
USDZ AR 拡張では, sceneLibrary
でシーンの切り替え(Variant 相当)をすることができます.
- シーン切り替えできるのは root の Prim の kind を
sceneLibrary
にする - 切り替えするシーンは
over
で定義(プライマリのシーンはdef
) - Prim meta に
sceneName
でシーン名を記載可能
Variant よりもこちらのほうが理解しやすい(and 実装しやすい)ですね.
TinyUSDZ ではとりあえず読み込みは対応しています https://github.com/syoyo/tinyusdz/issues/36
(Handy なシーン切り替え機能はまだ)