🌊

SOLARISで理解するレイヤー・ステージ

2021/07/04に公開

https://zenn.dev/remiria/articles/usd-stagelayer

前回書いたこちらの記事「Pythonで始めるUSD」をベースに
これをHoudini SOLARISに置き換えることで、さらに理解を深めてみようというのが
今回の記事になります。

ステージ

HoudiniのLOP(SOLARIS)はUSDの構造を非常にわかりやすく表現しています。

LOPの世界は「Stage」と呼ばれる空間で操作します。
USDにおけるステージとは、前回にも書きましたが
複数のレイヤーを合成した結果できあがったシーングラフ
のことを指しています。

つまり、このStage以下でノードを組み合わせて出来上がった結果=ステージ
USDの合成した結果であることから、LOPは Stage という名前がつけら得れているのだと思います。
わかりやすいです。

レイヤーとノード

ステージとは、複数のレイヤーが合成された結果できあがるものであることから
このLOP世界内におけるノードが何を表しているかというと
1つのノードが1つのレイヤー扱いになっています。

たとえば、このようなシンプルなキューブのノードを作成してみます。
このノードは、

Inspect Active Layer からレイヤーの中身を確認すると、

#sdf 1.4.32
(
    framesPerSecond = 24
    metersPerUnit = 1
    timeCodesPerSecond = 24
)

def HoudiniLayerInfo "HoudiniLayerInfo" (
    customData = {
        string HoudiniCreatorNode = "/stage/cube1"
        string[] HoudiniEditorNodes = ["/stage/cube1"]
    }
)
{
}

def Cube "cube1" (
    customData = {
        int HoudiniPrimEditorNodeId = 13
    }
)
{
    float3[] extent = [(-1, -1, -1), (1, 1, 1)]
    double size = 2
    matrix4d xformOp:transform = ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) )
    uniform token[] xformOpOrder = ["xformOp:transform"]
}

アノニマスレイヤー(メモリ上にのみ存在するレイヤー)となっていて
そのレイヤーには、「こういうPrimを作って欲しい」というオピニオン(意見)が
記述されています。

更にノードを詳しくみていくと、

ノードのInputとOutputを見てみると、
ノードのInputは「Input Stage」、Output側が「Output Stage」となっています。

つまりは、ノードはレイヤーで
「あるステージをInputとして受け取り、ノードのレイヤーを合成してその結果のステージをOutput」する
という構造になっていることがわかります。

いったんまとめると、

  1. LOP世界はステージ
  2. 1つのノードはレイヤー
  3. ノードはステージを受け取って、自分のレイヤー(意見)を合成してその結果のステージをOutputする

という関係性になっています。

SceheGraphTree

SOLARISにはSceneGraphTreeというパネルが存在しています。
このパネルが何を意味するかというと「現在選択しているノード(レイヤー)まで合成した結果のステージ」になっています。

例として、このようなノード構成になっていたとします。
SphereレイヤーとCubeレイヤーがMerge(サブレイヤー)されています。

選択を切り替えてみると、選んでいるノード(レイヤー)までの
シーングラフになっていることがわかります。

load Layer

このLOPにおけるレイヤーとステージについてを理解した上で
usdファイルをロードするノードを見ていきます。

USDは1つのファイルのことを「レイヤー」と呼びます。
レイヤーは、最終的にどのようなステージになるかわかりません。

たとえば、このノードでKitchen_setをロードした場合。
LoadLayerノードは、指定したFileをロードして、

Inputで受け取ったステージに対して、 Kitchen_set.usd を合成した結果の
ステージをOutputします。
なので、Load「Layer」ですがステージとしてOutputできているわけです。

Sphereレイヤーに、Kitchen_setレイヤーを合成した結果のステージは
このようになります。

RootLayer

ノード1つがレイヤー、レイヤーはステージをうけとり自分の意見を合成して
その結果のステージを出力します。
このときに、最後の末端(あるいは選択しているノード、レイヤー)のことを
USDではルートレイヤーと呼びます。

ステージは、複数のレイヤーを合成した結果であり
単純にステージを受け取った場合は「どのレイヤーを編集するか」というのは
わかりません。
ので、ステージには「EditTarget」という概念があり
ステージを経由してシーングラフを操作した場合「EditTarget」に指定された
レイヤーに対して編集が行われます。

で。
デフォルトではこの「EditTarget」は「ルートレイヤー」が指定されています。
LOPの場合は、特に変更していない場合、
末端の(選択しているノード)のレイヤーがルートレイヤー扱いになります。
なので、ノードの挙動は

  1. あるステージにサブレイヤーでレイヤーを追加
  2. そのレイヤーをEditTargetに指定して意見をレイヤーに書く
  3. 結果のステージを返す

となります。

レイヤーと分割

Houdiniのノードはレイヤーと同等という説明にあるとおり
ノードを接続していくと ## Layers という表示がノードの右下に表示されます。
これは、ある地点(この場合は loadlayerノードまで)のステージに
どれだけのレイヤー(なにかしらの意見を持つレイヤー)があるかどうかを
示しています。

ある地点までの合成結果=ステージ
1つのノード=レイヤー

なので、ノードを増やせばそれだけレイヤーは増えていきます。

たとえばこのような構成の場合。
Cubeレイヤー(Cubeを作れという意見を持つレイヤー)
Sphereレイヤー(Sphereを作れという意見を持つレイヤー)
Kitchen_setレイヤー(Kitchen_set.usdというレイヤー)

これらはすべて別のUSDファイル扱いになっています。
そしてその結果できあがっているステージは
「3つのレイヤー(3つのファイルを持つ)を持つステージ」
になりました。

ノード1つがレイヤーとして扱われていても、それだと粒度が細かくなりすぎて
管理できなくなります。

なので、ある程度書くノードごとの意見をとりまとめて
1つのレイヤーにまとめる処理を「Flatten」と呼び

Mergeノードの「Flatten Layers」を選択すると、
Mergeの入力されたステージの意見を1つのレイヤーにとりまとめることができます。

これで、
「Cubeをつくる・Sphereを作る意見を持つレイヤー」と
「Kitchen_setのレイヤー」
2つのレイヤーになり、
最終的に1つのステージが出来上がります。

まとめ

こんなかんじで、SOLARIS(LOP)の世界は
USDのレイヤーやコンポジションをノードでそのまま表現したもの...というのが
なんとなくわかるのではないかなと思います。

なので、前回のUSD+Pythonで説明した内容をHoudiniSOLARIS上で説明すると
USDの理解もSOLARISの理解もより理解しやすいのではないかな?
とおもいます。

GitHubで編集を提案

Discussion