USD VariantSet のメモ

シーンデータの切り替え(switch のようなもの)ができる Variant の機能.
構文としてはちょっとわかりにくい.

## しくみ

- Prim meta の `variantSets` で variant の名前を列挙
- Prim meta の `variants` では, dictionary でデフォルト選択の variant を指定
  - ややこしいが, 変数名は `variantSets` と対応するものである必要がある(xformOps の場合と同様と考えるとよいかも).
- Prim body(statement) で `variantSet` で Variant 要素を指定する
  - これも Prim meta の `variantSets` と紛らわしいが, Prim 本体のは `variantSet` で `s` がつかないことに注意.
  
Prim や Property meta 内に `variantSet` を定義することはできない.

Property meta 内に `variantSets`, `variants` を定義することはできない(たぶん. 要検証)

## variantSet 構文

- `"name" ( ... ) { .. }` : Prim meta と Prim body(property or child Prim) を定義
- `"name" { over "primname" ( ... ) { ... } }` : child Prim として定義

ただし後者は `"name" ( ... ) { over "primname" ...} } ` と 考えると実質的には構文は前者で表現できると思われる.

また, variantSet 内での Prim spec は def なども使えるが, 通常は over であろう(既存のを上書き) 

### variantSet はネスト可能

variantSet はネストして定義可能である.

## 評価順

```
def "bora" (
    append variantSets = ["shapeVariant", "ashapeVariant2"]
    variants = {
      string ashapeVariant2 = "Cone"
      string shapeVariant = "Capsule"
    }
)
{
    variantSet "ashapeVariant2" = {
        "Capsule" ( hidden = 1 ) {
            float mycapsule = 0.4
        }
        "Cone" ( hidden = 1 ) {
            float mycone = 0.2
        }
    }

    variantSet "shapeVariant" = {
        "Capsule" ( hidden = 0 ) {
            float mycapsule = 1.3
        }
        "Cone" ( hidden = 0 ) {
            float mycone = 2.3
        }
    }

}
```

`usdcat --flatten input.usda`

```
#usda 1.0
(
    doc = """Generated from Composed Stage of root layer /mnt/data/work/tinyusdz/tests/usda/variantSet-meta-001.usda
"""
)

def "bora" (
    hidden = false
)
{
    float mycapsule = 1.3
    float mycone = 0.2
}
```

Prim の meta と properties は variantSets の**最後要素側**から評価される模様("shapeVariant", "ashapeVariant2" を入れ替えると `hidden = true` となる)

xformOpOrder の評価順と合わせてなのかもしれません(xformOpOrder は最後要素側から評価される).

prepend に変えても変化はなかった.

append, prepend などの listedit op はほかの composition との優先順で, variantSet の評価順には影響ないっぽい.

https://openusd.org/release/glossary.html#list-editing

また, local 変数(prim metadatum, properties など)がすでにある場合は, LIVRPS に従って local が強いので, variantSet では置き換わらない(すくなくとも `def` の場合).

## Path

`/bora{shapeVariant=Cone}` のようにして `{tag=varname}` の形で表現される.

```
#usda 1.0

def "bora" (
    variants = {
        string shapeVariant = "Capsule"
    }
    append variantSets = "shapeVariant"
)
{
    variantSet "shapeVariant" = {
        "Capsule" {
            float mycapsule = 1.3

            def "dora"
            {
                float mydora = 10.2
            }

        }
        "Cone" {
            float mycone = 2.3

        }
    }
}
```

の構成では, Crate(USDC) では Path は以下のように構成される.

```
Path[0] = /
Path[1] = /bora
Path[2] = /bora{shapeVariant=}
Path[3] = /bora{shapeVariant=Capsule}
Path[4] = /bora{shapeVariant=Capsule}.mycapsule
Path[5] = /bora{shapeVariant=Capsule}dora
Path[6] = /bora{shapeVariant=Capsule}dora.mydora
Path[7] = /bora{shapeVariant=Cone}
Path[8] = /bora{shapeVariant=Cone}.mycone
```

`{shapeVariant=}` は擬似的な Prim 相当. SpecType は SpecTypeVariantSet となる.
variant に childPrim(variantChildren)がつく場合は '/' で区切らない模様.

variant `/bora{shapeVariant=Capsule}` も Prim 相当に対応する(少なくとも実装上は property path ではない).

ただ, `/bora{shapeVariant=}` (SpecTypeVariantSet) と ` /bora{shapeVariant=Capsule}` (SpecTypeVariant) は親子関係ではなく, 同じ階層にとなる. 

`/bora{shapeVariant=Capsule}.mycapsule` は,

`/bora` (prim) -> `{shapeVariant=Capsule}` (variantPrim?)  -> `.mycapsule` (property)

と分解される.

(あと `[` `]` で表現されるものもある https://graphics.pixar.com/usd/release/api/class_sdf_path.html )

## USDC(Crate) での定義

SpecTypeVariant と SpecTypeVariantSet がある.

### SpecTypeVariant

Prim(variantPrim?) 相当.

### SpecTypeVariantSet

variant のリスト

```
token[] variantChildren
```

だけを持つ spec(path) のようである. SpecTypeVariant の子になる.

Nested VariantSet の場合, Variant の parent は SpecTypeVariant となる(SpecTypeVariantSet ではない).

したがって parent の SpecTypeVariantSet を探索する必要がある