Op API

Op APIは、シーングラフの操作と属性の変更のための強力なC ++プラグインインターフェイスを提供します。すべてのKatanaの同梱のOpはOp APIで記述されています。このAPIを使用すると、シーンデータを任意に作成および操作できるプラグインを作成できます。Opには、任意の数のシーングラフ入力を与え、それらの入力から任意の場所の属性データを検査し、現在の場所で属性を作成、削除、および変更できます。Opsは、子ロケーションを作成および削除したり、自分自身を削除することもできます。

言い換えれば、あなたができることは何でもKatanaノード、Opで実行できます。Opsでできることの例は次のとおりです。

コンテキスト対応のジェネレーターとインポーターを使用して、

高度なカスタムマージ操作、

階層のインスタンス化、

フラグメントパーツからネットワークマテリアルを構築する。

群集のジオメトリを生成する処理。

注意:  Op APIは、Scene Graph GeneratorおよびAttribute Modifier Plug-in APIに取って代わるものですが、2.0v1以降のバージョンでも引き続き使用できますKatana

このセクションでは、Op APIの次の要素について説明します。

The cook interface、それが何であるか、どのようにGeolib3に適合するか。

Op arguments子に渡される引数を変更します。

Scene graph creation階層トポロジ管理。シーングラフの場所を作成および削除する方法や、Opの実行場所を制御する方法が含まれます。

Reading scene graph input潜在的に多くの入力、および関連する問題から。

CEL一般的なタスクを実行するために、Opライターとして使用できるその他のユーティリティ関数。

Integrating your Opノードグラフで。

上記の概念の具体例は、 $KATANA_HOME/plugins/Src/Ops多数のコアOpsのソースコードが保持されるディレクトリ。以下は、これらのOpの一部の簡単な概要と、それらが現在使用されている場所の例です。

AttributeCopy-AttributeCopyノードの実装を提供します。これは、シーンのあるブランチから別のブランチの場所の属性をコピーします。

AttributeSet-AttributeSetノードのバックエンド。これにより、着信シーングラフの任意の場所で属性を設定、変更、および削除できます。

HierarchyCopy-AttributeSet Opと同様に、HierarchyCopyノードのバックエンドであり、シーングラフ階層の任意の部分をシーングラフの他の部分にコピーできます。

プルーン-シーンから指定したCEL式に一致する場所を削除します。

StaticSceneCreate-指定した一連の引数に基づいて静的階層を生成します。このOpはHierarchyCreateの中核であり、他のOpとノードによって広範囲に使用され、必要な場所と属性の階層を生成します。たとえば、CameraCreateノードはStaticSceneCreate Opを使用して、カメラの位置に必要な階層を生成します。

クックインターフェース

クックインターフェースは、Geolib3がOpの機能を実装するために提供するインターフェースです。Opが実行されると、このインターフェースの有効なインスタンスが渡されますcook()メソッドが呼び出されます。前述のように、このインターフェイスは、引数の問い合わせ、シーングラフトポロジの作成または変更、およびシーングラフ入力の読み取りを可能にするメソッドを提供します。クックインターフェースで利用可能なメソッドの完全なリストを見つけることができます$KATANA_HOME/plugin_apis/include/FnGeolib/op/FnGeolibCookInterface.h.

操作引数

前に説明したように、Opsには2つの形式の入力が提供されます。上流のOpsによって作成されるシーングラフ入力とOpの引数。これらはOpに渡され、実行方法を設定します。ユーザー引数の例には、Opを実行する場所を記述するCELステートメント、ロードするジオメトリキャッシュを指すファイルパス、またはOpが作成する子の場所のリストが含まれます。

まず、引数を調べる単純なケースを見てから、引数を子の場所に再帰的に渡す一般的なパターンを見ていきます。

引数の読み取り

引数は、のインスタンスとしてOpに渡されますFnAttributeクラス。クックインターフェイスには、Op引数を取得するための次の関数呼び出しがあります。

FnAttribute::Attribute getOpArg(     const std::string& specificArgName = std::string()) const;

たとえば、StaticSceneCreate Opは、というGroupAttributeを受け入れますa特定の場所に設定する値を含む属性のリストが含まれます。これは次のように表示されます。

StaticSceneCreateはa次のような引数:

FnAttribute::GroupAttribute a = interface.getOpArg("a"); if (a.isValid()) {     for (int i = 0; i < a.getNumberOfChildren(); ++i)     {         interface.setAttr(a.getChildName(i), a.getChildByIndex(i));     } }

注意:  を使用して属性を取得した後、属性の有効性を確認することが重要ですisValid() コール。クックインターフェースから属性が返されるたびに、属性の有効性を確認する必要があります。

子の場所に引数を渡す

Opが実行される子の場所に引数を渡す一般的な再帰的アプローチがあります。StaticSceneCreate Opは、このパターンを非常にうまく例示しています。

StaticSceneCreateは、属性を設定し、渡された引数の1つの値に基づいて子の場所の階層を作成します。この引数は、各場所について以下を説明するGroupAttributeです。

a -属性値

c -子の場所の名前

x -その場所で追加のOpを評価する必要があるかどうか

作成した子に引数を渡すために、下層を剥がしますc引数とその子に渡します。概念的には、次のように考えることができます(詳細aそしてx簡潔にするために省略されています):

現在の場所で実行されているOpが読み取りますac 、そしてx。の各子GroupAttributeについてc GroupAttributeの名前(child1 / child2など)で新しい子の場所を作成し、GroupAttributeをその場所の引数として渡します。

コードで子を作成するには、次の主要な関数呼び出しを使用します。

void createChild(const std::string& name,                  const std::string& optype = "",                  const FnAttribute::Attribute& args = FnAttribute::Attribute(),                  ResetRoot resetRoot = ResetRootAuto,                  void* privateData = 0x0,                  void (*deletePrivateData)(void* data) = 0x0);

createChild()関数は、Opが評価されている場所の子を作成します。この関数は、ランタイムでそこで実行する必要があるOpのタイプ(デフォルトでは、呼び出したOpと同じタイプのOp createChild())およびそれに渡される引数。StaticSceneCreateでは、これは次のようになります。

for (int childindex = 0; childindex < c.getNumberOfChildren(); ++childindex) {     std::string childName = c.getChildName(childindex);     FnAttribute::GroupAttribute childArgs = c.getChildByIndex(childindex);     interface.createChild(childName, "", childArgs); }

シーングラフ作成

Opの主なタスクの1つは、シーングラフの位置と属性を作成することです。Op APIは、これを行うための豊富な機能セットを提供します。シーングラフトポロジを変更し、Opの実行を制御するために使用できる5つの主要な機能があります。これについては、以下で説明します。

注意:  ここで説明する一連の関数と、 シーングラフ入力の読み取り。ここで説明するすべての機能は、 output of an Op at a given Scene Graph location。で説明されている機能シーングラフ入力の読み取りシーングラフデータの読み取りのみに関連するinput不変である特定のシーングラフ位置でのOpの。

setAttr()関数

void setAttr(const std::string& attrName,              const FnAttribute::Attribute& value,              const bool groupInherit = true);

setAttr()関数を使用すると、Opが現在評価されている場所に属性値を設定できます。たとえば、 StringAttribute Opのルートロケーションでは、次のことができます。

if (interface.atRoot()) {     interface.setAttr("myAttr", FnAttribute::StringAttribute("Val")); }

Opが現在評価されている場所以外の場所に属性を設定することはできません。あなたが電話した場合setAttr()同じ場所で特定の属性名を複数回使用した場合、最後に呼び出されたものが使用されます。のgroupInheritパラメータは、属性をその子によって継承する必要があるかどうかを決定するために使用されます。

注意:  以来setAttr() Opの出力に値を設定し、 getAttr()が呼び出された場合、指定された入力で不変の値を読み取りますsetAttr()直後に続くgetAttr()、結果はまだ関連する入力からの値であり、 setAttr()

createChild()関数

void createChild(const std::string& name,                  const std::string& optype = "",                  const FnAttribute::Attribute& args = FnAttribute::Attribute(),                  ResetRoot resetRoot = ResetRootAuto,                  void* privateData = 0x0,                  void (*deletePrivateData)(void* data) = 0x0);

createChild()関数を使用すると、Opが評価されているシーングラフの場所の下に子を作成できます。最も単純なケースでは、作成する場所の名前と、その場所で評価されるOpに渡す引数が必要です。例えば:

interface.createChild(childName, "", childArgs);

optypeを空の文字列として指定すると、子の作成と呼ばれる同じOpが子の場所で評価されます。ただし、他のoptypeを指定して、代わりに実行することができます。

注意:  への複数の呼び出しcreateChild()同じ名前の子の場所の場合、最後に指定されたoptypeが使用されます。つまり、 createChild()事前の呼び出しをマスクします。

resetRootパラメーターは、次の3つの値のいずれかを取ります。

ResetRootTrue -新しい場所で評価されたOpのルートの場所は、新しい場所のパスにリセットされます。

ResetRootAuto (デフォルト)-optypeがOp呼び出しと異なる場合にのみ、ルートの場所がリセットされますcreateChild()

ResetRootFalse -新しい場所で評価されたOpのルートの場所は、呼び出されたOpから継承されますcreateChild()

このパラメーターは、 rootLocation Opが子ロケーションで実行される場合。

execOp()関数

void execOp(const std::string& opType,             const FnAttribute::GroupAttribute& args);

Geolib3ランタイムがOpTreeを評価する頃には、それは静的で修正されています。クックインターフェースは、OpTreeの構築時に宣言されなかったOpsがOpTreeの評価時に実行されるように要求できる多くの関数を提供します。

私たちはすでにどのように見てきましたcreateChild()これにより、子の場所で実行されるOpを指定できるようになります。のexecOp()関数を使用すると、Opが別のOpの実行を直接呼び出すことができ、元のOpTreeで直接宣言されていないOpsを評価する別のメカニズムが提供されます。これはcreateChild()動作、さまざまな方法で子の場所で実行する異なるOpを宣言します。

これは、別のOpのワンショット実行と見なされる必要があります。

で指定されたOp execOp()呼び出しは、呼び出し元と同じルートロケーションで同じロケーションで実行されているかのように評価されます。

あなたが見ることができますexecOp() StaticSceneCreate Opで動作中。Opタイプはx引数:

// Exec some ops? FnAttribute::GroupAttribute opGroups = interface.getOpArg("x"); if (opGroups.isValid()) {     for (int childindex = 0; childindex < opGroups.getNumberOfChildren();          ++childindex)     {          ...          if (!opType.isValid() || !opArgs.isValid())          {              continue;          }          interface.execOp(opType.getValue("", false), opArgs);      } }

deleteSelf()関数

void deleteSelf();

これまで、シーングラフにデータを追加するメカニズムのみを見てきましたが、 deleteSelf()関数と関連する関数deleteChild()シーングラフから場所を削除できます。それらの動作は自明ですが、副作用は直観的ではなく、で詳しく説明されていますシーングラフ入力の読み取り。ただし、現時点では、Prune Opがどのように見えるかの例は、 deleteSelf()関数呼び出しは次のとおりです。

// Use CEL Utility function to evaluate CEL expression FnAttribute::StringAttribute celAttr = interface.getOpArg("CEL"); if (!celAttr.isValid())     return;   Foundry::Katana::MatchesCELInfo info; Foundry::Katana::MatchesCEL(info, interface, celAttr);   if (!info.matches)     return; // Otherwise, delete myself interface.deleteSelf();   return;

stopChildTraversal()関数

void stopChildTraversal();

stopChildTraversal() functionは、Opを実行する場所を制御できる機能の1つです。評価される現在の場所の子でこのOpの実行を停止します。例として最もよく説明されています。

入力シーンがあるとします:

/root

/world

/light

私たちが望むのは:

/root

/world

/geo

/taco

/light

したがって、StaticSceneCreate Opを使用して、開始場所/ root / worldにこの追加の階層を作成します。

/geo

/taco

ただし、呼び出さない場合stopChildTraversal() StaticSceneCreate Opが/root/worldこの操作は両方で実行されます/root/worldそして/root/world/light、 その結果:

/root

/world

/geo

/taco

/light

/geo

/taco

要約する、 stopChildTraversal()入力に存在する子ロケーションでOpが自動的に評価されないようにします。最も一般的な使用法stopChildTraversal()効率のためです。たとえば、CEL式を見て、このOpが現在の階層よりも階層内のより深い場所で効果がないと判断できる場合は、次のように呼び出すことをお勧めします。 stopChildTraversal()子の場所でこのOpを呼び出さないようにします。

シーングラフ入力の読み取り

アップストリームOpsによって生成された入力シーングラフを読み取る関数の範囲があります。これらの関数はすべて、読み取り機能のみを許可します。入力シーンは不変です。

getNumInputs()関数

int getNumInputs() const;

Opは、他の複数のOpからの出力を入力として持つことができます。これの明らかな使用例は、異なるOpTreeによって生成された複数のシーングラフを単一のシーングラフにマージしたり、2つのシーングラフ状態の属性値を比較したり、あるシーングラフを別のシーングラフにコピーしたりする場合です。のgetNumInputs()関数を使用すると、入力として持っているOpの数を決定できます。これは、シーングラフデータのOpTreeのさまざまなブランチを調べる前兆です。

警告:  Geolib3の遅延処理モデルを考えると、次のような「get」関数は注目に値します。 getAttr()getPotentialChildren()doesInputExist() 、まだ計算されていないシーングラフ情報を要求する場合があります。

このような場合、要求された場所の準備が整うと、(例外を使用して)Opの実行が中止され、再スケジュールされます。したがって、Opの作成者は、「(...)」ですべての例外を盲目的にキャッチしようとするべきではなく、さらに、例外セーフコードを作成しようとするべきです。

ユーザーOpがこれらの例外の1つを誤ってキャッチした場合、ランタイムはこれを検出し、結果を無効と見なし、シーングラフにエラーを生成します。

Opがデフォルトの入力場所(およびインデックス)またはその親からのみ読み取りを行っている場合、「recooks」は発生しません。ただし、入力場所のパスまたは入力インデックスのいずれかにある分散アクセスクエリの場合、「recooks」が発生する可能性があります。Opが多数の場所から分散アクセスクエリを実行する必要がある場合、そうでなければ不幸なパフォーマンス特性が生じるため、API呼び出し- prefetch() -が利用可能であり、後で詳しく説明します。

getAttr()関数

FnAttribute::Attribute getAttr(     const std::string& attrName,     const std::string& inputLocationPath = std::string(),     int inputIndex = kFnKatGeolibDefaultInput) const;

多くの場合、何らかのアクションを実行するか、別の属性に格納された結果に基づいて値を計算する必要があります。のgetAttr()関数を使用すると、属性名とシーングラフの場所のパス(絶対または相対)を指定して、着信シーングラフの任意の部分を調べることができます。さらに、特定の入力インデックスを指定して属性値を取得できます。この値は、次の結果よりも小さくなければなりません。 getNumInputs()。getAttrは、Opへの入力で見られる値を常に返すことに注意することが重要です。自分またはexecOpで呼び出された別のOpによって既に作成されたsetAttrsを検討する場合は、getOutputAttrを使用する必要があります。

次の図は、このいくつかの微妙な点を示しています。最も重要なことは、execOp OpのgetAttrは、クエリの場所が現在の場所である場合のみ、呼び出し元のOpの結果を表示します。 'Opグラフで。

getPotentialChildren()関数

FnAttribute::StringAttribute getPotentialChildren(     const std::string& inputLocationPath = std::string(),     int inputIndex = kFnKatGeolibDefaultInput) const;

シーングラフ作成関数deleteSelf() そのような呼び出しの結果は、最初に現れたよりも微妙であることに注意して導入されました。アップストリームOpが評価され、子を作成する場合、ダウンストリームOpがそれらを削除する能力を持っている場合、アップストリームOpは、ダウンストリームOpがそれらの子の場所で評価された後に作成する子が潜在的に存在する可能性があることを示すまでしか行けません。これは、Opがそのような場所で評価されたときにダウンストリームOpが何をするかについての知識を持っていないためです。その範囲で、 getPotentialChildren() Opの入力で特定の場所のすべての子のリストを返します。

prefetch()関数

void prefetch(const std::string& inputLocationPath = std::string(),               int inputIndex = kFnKatGeolibDefaultInput) const;

Opのクック関数のコードでできるだけ早くprefetch()を使用することにより、適切なコードプラクティスを維持してください。

prefetch()関数を使用して、シーングラフの位置間の依存関係を示すことができます。例えば:

/root/world/geo/a may call prefetch() for /root/world/geo/b because during the processing of /root/world/geo/a, attributes present at ./bが必要になります。

CELとユーティリティ

次のような、Opsを完了するために頻繁に必要なタスクがいくつかあります。

場所の階層を作成し、

CEL式の引数に基づいてOpを実行するかどうかの決定、

シーングラフを介してユーザーにエラーを報告する

境界ボックスなど、使いやすい形式で既知の属性値を取得します。

現在、これらのユーティリティのヘッダーは次の場所にあります。

$ KATANA_HOME / plugin_apis / include / FnGeolib / op / FnGeolibCookInterface.h

$ KATANA_HOME / plugin_apis / include / FnGeolib / util / *

ユーティリティの実装は次の場所にあります。

$ KATANA_HOME / plugin_apis / src / FnGeolib / op / FnGeolibCookInterfaceUtils.cpp

$ KATANA_HOME / plugin_apis / src / FnGeolib / util / *

これらのユーティリティの多くは自己文書化されており、同様のパターンに従います。次の例は、CELマッチングユーティリティの使用方法を示しています。

// Should we run here? If not, return. FnAttribute::StringAttribute celAttr = interface.getOpArg("CEL"); if (!celAttr.isValid())     return; Foundry::Katana::MatchesCELInfo info; Foundry::Katana::MatchesCEL(info, interface, celAttr); if (!info.canMatchChildren) {     interface.stopChildTraversal(); } if (!info.matches)     return;

上記の例では、いくつかのことが達成されます。

1.   CEL式がいずれかの子と一致する可能性があるかどうかを判断し、一致しない場合は、子の場所でこのOpを評価しないようランタイムに指示します。
2.   この場所で実行する必要があるかどうかを判断し、そうでない場合は早期に戻ります。

Opsを記述する際の生産性を高めることができるため、利用可能なユーティリティ関数の範囲を自由に探索してください。